From 70efd9620218608f4855b2377ca3ee6d57fc58cf Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:01:14 +0200 Subject: [PATCH 01/31] gitignore: Un-ignore content of vendor directory --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 1de278f2a..613970920 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ tmp/* # ignore goland project files .idea/ + +# Un-ignore anything in the vendor directory +!vendor/** \ No newline at end of file From 327cdb5f16e1f700f02f01d26d21ea3d5fc7f8eb Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 22:39:46 +0200 Subject: [PATCH 02/31] gomod: Switch to github.com/google/uuid --- go.mod | 3 +- go.sum | 6 +- vendor/github.com/google/uuid/CHANGELOG.md | 31 +++ vendor/github.com/google/uuid/CONTRIBUTING.md | 2 +- vendor/github.com/google/uuid/hash.go | 6 + vendor/github.com/google/uuid/time.go | 21 +- vendor/github.com/google/uuid/uuid.go | 79 +++++- vendor/github.com/google/uuid/version6.go | 56 ++++ vendor/github.com/google/uuid/version7.go | 104 ++++++++ vendor/github.com/satori/go.uuid/.travis.yml | 23 -- vendor/github.com/satori/go.uuid/LICENSE | 20 -- vendor/github.com/satori/go.uuid/README.md | 65 ----- vendor/github.com/satori/go.uuid/codec.go | 206 --------------- vendor/github.com/satori/go.uuid/generator.go | 239 ------------------ vendor/github.com/satori/go.uuid/sql.go | 78 ------ vendor/github.com/satori/go.uuid/uuid.go | 161 ------------ vendor/modules.txt | 5 +- 17 files changed, 292 insertions(+), 813 deletions(-) create mode 100644 vendor/github.com/google/uuid/version6.go create mode 100644 vendor/github.com/google/uuid/version7.go delete mode 100644 vendor/github.com/satori/go.uuid/.travis.yml delete mode 100644 vendor/github.com/satori/go.uuid/LICENSE delete mode 100644 vendor/github.com/satori/go.uuid/README.md delete mode 100644 vendor/github.com/satori/go.uuid/codec.go delete mode 100644 vendor/github.com/satori/go.uuid/generator.go delete mode 100644 vendor/github.com/satori/go.uuid/sql.go delete mode 100644 vendor/github.com/satori/go.uuid/uuid.go diff --git a/go.mod b/go.mod index a31434a7e..da159f9b5 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/go-redis/redis/v7 v7.4.1 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golangci/golangci-lint v1.51.2 + github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 @@ -32,7 +33,6 @@ require ( github.com/prometheus/client_golang v1.12.1 github.com/rs/xid v1.2.1 github.com/rs/zerolog v1.17.2 - github.com/satori/go.uuid v1.2.0 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 github.com/sony/gobreaker v0.4.1 github.com/spf13/cobra v1.6.1 @@ -108,7 +108,6 @@ require ( github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/uuid v1.3.1 // indirect github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect diff --git a/go.sum b/go.sum index 7e236db48..7e809a2f7 100644 --- a/go.sum +++ b/go.sum @@ -312,8 +312,8 @@ github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -572,8 +572,6 @@ github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tM github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.23.0 h1:01h+/2Kd+NblNItNeux0veSL5cBF1jbEOPrEhDzGYq0= github.com/sashamelentyev/usestdlibvars v1.23.0/go.mod h1:YPwr/Y1LATzHI93CqoPUN/2BzGQ/6N/cl/KwgR0B/aU= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/securego/gosec/v2 v2.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgIAtw= github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md index 2bd78667a..7ec5ac7ea 100644 --- a/vendor/github.com/google/uuid/CHANGELOG.md +++ b/vendor/github.com/google/uuid/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) + + +### Features + +* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) + + +### Bug Fixes + +* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) +* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) + +## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) + + +### Features + +* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) + +## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) + + +### Features + +* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) + +### Fixes + +* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) + ## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md index 556688872..a502fdc51 100644 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -11,7 +11,7 @@ please explain why in the pull request description. ### Releasing -Commits that would precipitate a SemVer change, as desrcibed in the Conventional +Commits that would precipitate a SemVer change, as described in the Conventional Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) to create a release candidate pull request. Once submitted, `release-please` will create a release. diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go index b404f4bec..dc60082d3 100644 --- a/vendor/github.com/google/uuid/hash.go +++ b/vendor/github.com/google/uuid/hash.go @@ -17,6 +17,12 @@ var ( NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) Nil UUID // empty UUID, all zeros + + // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. + Max = UUID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + } ) // NewHash returns a new UUID derived from the hash of space concatenated with diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go index e6ef06cdc..c35112927 100644 --- a/vendor/github.com/google/uuid/time.go +++ b/vendor/github.com/google/uuid/time.go @@ -108,12 +108,23 @@ func setClockSequence(seq int) { } // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1 and 2 UUIDs. +// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. func (uuid UUID) Time() Time { - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - return Time(time) + var t Time + switch uuid.Version() { + case 6: + time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 + t = Time(time) + case 7: + time := binary.BigEndian.Uint64(uuid[:8]) + t = Time((time>>16)*10000 + g1582ns100) + default: // forward compatible + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + t = Time(time) + } + return t } // ClockSequence returns the clock sequence encoded in uuid. diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index a56138cc4..5232b4867 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -56,11 +56,15 @@ func IsInvalidLengthError(err error) bool { return ok } -// Parse decodes s into a UUID or returns an error. Both the standard UUID -// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the -// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex -// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both +// the standard UUID forms defined in RFC 4122 +// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, +// Parse accepts non-standard strings such as the raw hex encoding +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, +// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are +// examined in the latter case. Parse should not be used to validate strings as +// it parses non-standard encodings as indicated above. func Parse(s string) (UUID, error) { var uuid UUID switch len(s) { @@ -182,6 +186,59 @@ func Must(uuid UUID, err error) UUID { return uuid } +// Validate returns an error if s is not a properly formatted UUID in one of the following formats: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// It returns an error if the format is invalid, otherwise nil. +func Validate(s string) error { + switch len(s) { + // Standard UUID format + case 36: + + // UUID with "urn:uuid:" prefix + case 36 + 9: + if !strings.EqualFold(s[:9], "urn:uuid:") { + return fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // UUID enclosed in braces + case 36 + 2: + if s[0] != '{' || s[len(s)-1] != '}' { + return fmt.Errorf("invalid bracketed UUID format") + } + s = s[1 : len(s)-1] + + // UUID without hyphens + case 32: + for i := 0; i < len(s); i += 2 { + _, ok := xtob(s[i], s[i+1]) + if !ok { + return errors.New("invalid UUID format") + } + } + + default: + return invalidLengthError{len(s)} + } + + // Check for standard UUID format + if len(s) == 36 { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return errors.New("invalid UUID format") + } + for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { + if _, ok := xtob(s[x], s[x+1]); !ok { + return errors.New("invalid UUID format") + } + } + } + + return nil +} + // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // , or "" if uuid is invalid. func (uuid UUID) String() string { @@ -294,3 +351,15 @@ func DisableRandPool() { poolMu.Lock() poolPos = randPoolSize } + +// UUIDs is a slice of UUID types. +type UUIDs []UUID + +// Strings returns a string slice containing the string form of each UUID in uuids. +func (uuids UUIDs) Strings() []string { + var uuidStrs = make([]string, len(uuids)) + for i, uuid := range uuids { + uuidStrs[i] = uuid.String() + } + return uuidStrs +} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go new file mode 100644 index 000000000..339a959a7 --- /dev/null +++ b/vendor/github.com/google/uuid/version6.go @@ -0,0 +1,56 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "encoding/binary" + +// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. +// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. +// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 +// +// NewV6 returns a Version 6 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewV6 returns Nil and an error. +func NewV6() (UUID, error) { + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_high | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_mid | time_low_and_version | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |clk_seq_hi_res | clk_seq_low | node (0-1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | node (2-5) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + binary.BigEndian.PutUint64(uuid[0:], uint64(now)) + binary.BigEndian.PutUint16(uuid[8:], seq) + + uuid[6] = 0x60 | (uuid[6] & 0x0F) + uuid[8] = 0x80 | (uuid[8] & 0x3F) + + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + copy(uuid[10:], nodeID[:]) + nodeMu.Unlock() + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go new file mode 100644 index 000000000..3167b643d --- /dev/null +++ b/vendor/github.com/google/uuid/version7.go @@ -0,0 +1,104 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// UUID version 7 features a time-ordered value field derived from the widely +// implemented and well known Unix Epoch timestamp source, +// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. +// As well as improved entropy characteristics over versions 1 or 6. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 +// +// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. +// +// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). +// Uses the randomness pool if it was enabled with EnableRandPool. +// On error, NewV7 returns Nil and an error +func NewV7() (UUID, error) { + uuid, err := NewRandom() + if err != nil { + return uuid, err + } + makeV7(uuid[:]) + return uuid, nil +} + +// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). +// it use NewRandomFromReader fill random bits. +// On error, NewV7FromReader returns Nil and an error. +func NewV7FromReader(r io.Reader) (UUID, error) { + uuid, err := NewRandomFromReader(r) + if err != nil { + return uuid, err + } + + makeV7(uuid[:]) + return uuid, nil +} + +// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) +// uuid[8] already has the right version number (Variant is 10) +// see function NewV7 and NewV7FromReader +func makeV7(uuid []byte) { + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | ver | rand_a (12 bit seq) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |var| rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + _ = uuid[15] // bounds check + + t, s := getV7Time() + + uuid[0] = byte(t >> 40) + uuid[1] = byte(t >> 32) + uuid[2] = byte(t >> 24) + uuid[3] = byte(t >> 16) + uuid[4] = byte(t >> 8) + uuid[5] = byte(t) + + uuid[6] = 0x70 | (0x0F & byte(s>>8)) + uuid[7] = byte(s) +} + +// lastV7time is the last time we returned stored as: +// +// 52 bits of time in milliseconds since epoch +// 12 bits of (fractional nanoseconds) >> 8 +var lastV7time int64 + +const nanoPerMilli = 1000000 + +// getV7Time returns the time in milliseconds and nanoseconds / 256. +// The returned (milli << 12 + seq) is guarenteed to be greater than +// (milli << 12 + seq) returned by any previous call to getV7Time. +func getV7Time() (milli, seq int64) { + timeMu.Lock() + defer timeMu.Unlock() + + nano := timeNow().UnixNano() + milli = nano / nanoPerMilli + // Sequence number is between 0 and 3906 (nanoPerMilli>>8) + seq = (nano - milli*nanoPerMilli) >> 8 + now := milli<<12 + seq + if now <= lastV7time { + now = lastV7time + 1 + milli = now >> 12 + seq = now & 0xfff + } + lastV7time = now + return milli, seq +} diff --git a/vendor/github.com/satori/go.uuid/.travis.yml b/vendor/github.com/satori/go.uuid/.travis.yml deleted file mode 100644 index 20dd53b8d..000000000 --- a/vendor/github.com/satori/go.uuid/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: go -sudo: false -go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - 1.8 - - 1.9 - - tip -matrix: - allow_failures: - - go: tip - fast_finish: true -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -service=travis-ci -notifications: - email: false diff --git a/vendor/github.com/satori/go.uuid/LICENSE b/vendor/github.com/satori/go.uuid/LICENSE deleted file mode 100644 index 926d54987..000000000 --- a/vendor/github.com/satori/go.uuid/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (C) 2013-2018 by Maxim Bublis - -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. diff --git a/vendor/github.com/satori/go.uuid/README.md b/vendor/github.com/satori/go.uuid/README.md deleted file mode 100644 index 7b1a722df..000000000 --- a/vendor/github.com/satori/go.uuid/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# UUID package for Go language - -[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid) -[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid) -[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid) - -This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs. - -With 100% test coverage and benchmarks out of box. - -Supported versions: -* Version 1, based on timestamp and MAC address (RFC 4122) -* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1) -* Version 3, based on MD5 hashing (RFC 4122) -* Version 4, based on random numbers (RFC 4122) -* Version 5, based on SHA-1 hashing (RFC 4122) - -## Installation - -Use the `go` command: - - $ go get github.com/satori/go.uuid - -## Requirements - -UUID package requires Go >= 1.2. - -## Example - -```go -package main - -import ( - "fmt" - "github.com/satori/go.uuid" -) - -func main() { - // Creating UUID Version 4 - u1 := uuid.NewV4() - fmt.Printf("UUIDv4: %s\n", u1) - - // Parsing UUID from string input - u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - if err != nil { - fmt.Printf("Something gone wrong: %s", err) - } - fmt.Printf("Successfully parsed: %s", u2) -} -``` - -## Documentation - -[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project. - -## Links -* [RFC 4122](http://tools.ietf.org/html/rfc4122) -* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) - -## Copyright - -Copyright (C) 2013-2018 by Maxim Bublis . - -UUID package released under MIT License. -See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details. diff --git a/vendor/github.com/satori/go.uuid/codec.go b/vendor/github.com/satori/go.uuid/codec.go deleted file mode 100644 index 656892c53..000000000 --- a/vendor/github.com/satori/go.uuid/codec.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (C) 2013-2018 by Maxim Bublis -// -// 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. - -package uuid - -import ( - "bytes" - "encoding/hex" - "fmt" -) - -// FromBytes returns UUID converted from raw byte slice input. -// It will return error if the slice isn't 16 bytes long. -func FromBytes(input []byte) (u UUID, err error) { - err = u.UnmarshalBinary(input) - return -} - -// FromBytesOrNil returns UUID converted from raw byte slice input. -// Same behavior as FromBytes, but returns a Nil UUID on error. -func FromBytesOrNil(input []byte) UUID { - uuid, err := FromBytes(input) - if err != nil { - return Nil - } - return uuid -} - -// FromString returns UUID parsed from string input. -// Input is expected in a form accepted by UnmarshalText. -func FromString(input string) (u UUID, err error) { - err = u.UnmarshalText([]byte(input)) - return -} - -// FromStringOrNil returns UUID parsed from string input. -// Same behavior as FromString, but returns a Nil UUID on error. -func FromStringOrNil(input string) UUID { - uuid, err := FromString(input) - if err != nil { - return Nil - } - return uuid -} - -// MarshalText implements the encoding.TextMarshaler interface. -// The encoding is the same as returned by String. -func (u UUID) MarshalText() (text []byte, err error) { - text = []byte(u.String()) - return -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// Following formats are supported: -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", -// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", -// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" -// "6ba7b8109dad11d180b400c04fd430c8" -// ABNF for supported UUID text representation follows: -// uuid := canonical | hashlike | braced | urn -// plain := canonical | hashlike -// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct -// hashlike := 12hexoct -// braced := '{' plain '}' -// urn := URN ':' UUID-NID ':' plain -// URN := 'urn' -// UUID-NID := 'uuid' -// 12hexoct := 6hexoct 6hexoct -// 6hexoct := 4hexoct 2hexoct -// 4hexoct := 2hexoct 2hexoct -// 2hexoct := hexoct hexoct -// hexoct := hexdig hexdig -// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | -// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | -// 'A' | 'B' | 'C' | 'D' | 'E' | 'F' -func (u *UUID) UnmarshalText(text []byte) (err error) { - switch len(text) { - case 32: - return u.decodeHashLike(text) - case 36: - return u.decodeCanonical(text) - case 38: - return u.decodeBraced(text) - case 41: - fallthrough - case 45: - return u.decodeURN(text) - default: - return fmt.Errorf("uuid: incorrect UUID length: %s", text) - } -} - -// decodeCanonical decodes UUID string in format -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8". -func (u *UUID) decodeCanonical(t []byte) (err error) { - if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' { - return fmt.Errorf("uuid: incorrect UUID format %s", t) - } - - src := t[:] - dst := u[:] - - for i, byteGroup := range byteGroups { - if i > 0 { - src = src[1:] // skip dash - } - _, err = hex.Decode(dst[:byteGroup/2], src[:byteGroup]) - if err != nil { - return - } - src = src[byteGroup:] - dst = dst[byteGroup/2:] - } - - return -} - -// decodeHashLike decodes UUID string in format -// "6ba7b8109dad11d180b400c04fd430c8". -func (u *UUID) decodeHashLike(t []byte) (err error) { - src := t[:] - dst := u[:] - - if _, err = hex.Decode(dst, src); err != nil { - return err - } - return -} - -// decodeBraced decodes UUID string in format -// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" or in format -// "{6ba7b8109dad11d180b400c04fd430c8}". -func (u *UUID) decodeBraced(t []byte) (err error) { - l := len(t) - - if t[0] != '{' || t[l-1] != '}' { - return fmt.Errorf("uuid: incorrect UUID format %s", t) - } - - return u.decodePlain(t[1 : l-1]) -} - -// decodeURN decodes UUID string in format -// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in format -// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8". -func (u *UUID) decodeURN(t []byte) (err error) { - total := len(t) - - urn_uuid_prefix := t[:9] - - if !bytes.Equal(urn_uuid_prefix, urnPrefix) { - return fmt.Errorf("uuid: incorrect UUID format: %s", t) - } - - return u.decodePlain(t[9:total]) -} - -// decodePlain decodes UUID string in canonical format -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format -// "6ba7b8109dad11d180b400c04fd430c8". -func (u *UUID) decodePlain(t []byte) (err error) { - switch len(t) { - case 32: - return u.decodeHashLike(t) - case 36: - return u.decodeCanonical(t) - default: - return fmt.Errorf("uuid: incorrrect UUID length: %s", t) - } -} - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (u UUID) MarshalBinary() (data []byte, err error) { - data = u.Bytes() - return -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -// It will return error if the slice isn't 16 bytes long. -func (u *UUID) UnmarshalBinary(data []byte) (err error) { - if len(data) != Size { - err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) - return - } - copy(u[:], data) - - return -} diff --git a/vendor/github.com/satori/go.uuid/generator.go b/vendor/github.com/satori/go.uuid/generator.go deleted file mode 100644 index 3f2f1da2d..000000000 --- a/vendor/github.com/satori/go.uuid/generator.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) 2013-2018 by Maxim Bublis -// -// 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. - -package uuid - -import ( - "crypto/md5" - "crypto/rand" - "crypto/sha1" - "encoding/binary" - "hash" - "net" - "os" - "sync" - "time" -) - -// Difference in 100-nanosecond intervals between -// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). -const epochStart = 122192928000000000 - -var ( - global = newDefaultGenerator() - - epochFunc = unixTimeFunc - posixUID = uint32(os.Getuid()) - posixGID = uint32(os.Getgid()) -) - -// NewV1 returns UUID based on current timestamp and MAC address. -func NewV1() UUID { - return global.NewV1() -} - -// NewV2 returns DCE Security UUID based on POSIX UID/GID. -func NewV2(domain byte) UUID { - return global.NewV2(domain) -} - -// NewV3 returns UUID based on MD5 hash of namespace UUID and name. -func NewV3(ns UUID, name string) UUID { - return global.NewV3(ns, name) -} - -// NewV4 returns random generated UUID. -func NewV4() UUID { - return global.NewV4() -} - -// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. -func NewV5(ns UUID, name string) UUID { - return global.NewV5(ns, name) -} - -// Generator provides interface for generating UUIDs. -type Generator interface { - NewV1() UUID - NewV2(domain byte) UUID - NewV3(ns UUID, name string) UUID - NewV4() UUID - NewV5(ns UUID, name string) UUID -} - -// Default generator implementation. -type generator struct { - storageOnce sync.Once - storageMutex sync.Mutex - - lastTime uint64 - clockSequence uint16 - hardwareAddr [6]byte -} - -func newDefaultGenerator() Generator { - return &generator{} -} - -// NewV1 returns UUID based on current timestamp and MAC address. -func (g *generator) NewV1() UUID { - u := UUID{} - - timeNow, clockSeq, hardwareAddr := g.getStorage() - - binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) - binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) - binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) - binary.BigEndian.PutUint16(u[8:], clockSeq) - - copy(u[10:], hardwareAddr) - - u.SetVersion(V1) - u.SetVariant(VariantRFC4122) - - return u -} - -// NewV2 returns DCE Security UUID based on POSIX UID/GID. -func (g *generator) NewV2(domain byte) UUID { - u := UUID{} - - timeNow, clockSeq, hardwareAddr := g.getStorage() - - switch domain { - case DomainPerson: - binary.BigEndian.PutUint32(u[0:], posixUID) - case DomainGroup: - binary.BigEndian.PutUint32(u[0:], posixGID) - } - - binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) - binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) - binary.BigEndian.PutUint16(u[8:], clockSeq) - u[9] = domain - - copy(u[10:], hardwareAddr) - - u.SetVersion(V2) - u.SetVariant(VariantRFC4122) - - return u -} - -// NewV3 returns UUID based on MD5 hash of namespace UUID and name. -func (g *generator) NewV3(ns UUID, name string) UUID { - u := newFromHash(md5.New(), ns, name) - u.SetVersion(V3) - u.SetVariant(VariantRFC4122) - - return u -} - -// NewV4 returns random generated UUID. -func (g *generator) NewV4() UUID { - u := UUID{} - g.safeRandom(u[:]) - u.SetVersion(V4) - u.SetVariant(VariantRFC4122) - - return u -} - -// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. -func (g *generator) NewV5(ns UUID, name string) UUID { - u := newFromHash(sha1.New(), ns, name) - u.SetVersion(V5) - u.SetVariant(VariantRFC4122) - - return u -} - -func (g *generator) initStorage() { - g.initClockSequence() - g.initHardwareAddr() -} - -func (g *generator) initClockSequence() { - buf := make([]byte, 2) - g.safeRandom(buf) - g.clockSequence = binary.BigEndian.Uint16(buf) -} - -func (g *generator) initHardwareAddr() { - interfaces, err := net.Interfaces() - if err == nil { - for _, iface := range interfaces { - if len(iface.HardwareAddr) >= 6 { - copy(g.hardwareAddr[:], iface.HardwareAddr) - return - } - } - } - - // Initialize hardwareAddr randomly in case - // of real network interfaces absence - g.safeRandom(g.hardwareAddr[:]) - - // Set multicast bit as recommended in RFC 4122 - g.hardwareAddr[0] |= 0x01 -} - -func (g *generator) safeRandom(dest []byte) { - if _, err := rand.Read(dest); err != nil { - panic(err) - } -} - -// Returns UUID v1/v2 storage state. -// Returns epoch timestamp, clock sequence, and hardware address. -func (g *generator) getStorage() (uint64, uint16, []byte) { - g.storageOnce.Do(g.initStorage) - - g.storageMutex.Lock() - defer g.storageMutex.Unlock() - - timeNow := epochFunc() - // Clock changed backwards since last UUID generation. - // Should increase clock sequence. - if timeNow <= g.lastTime { - g.clockSequence++ - } - g.lastTime = timeNow - - return timeNow, g.clockSequence, g.hardwareAddr[:] -} - -// Returns difference in 100-nanosecond intervals between -// UUID epoch (October 15, 1582) and current time. -// This is default epoch calculation function. -func unixTimeFunc() uint64 { - return epochStart + uint64(time.Now().UnixNano()/100) -} - -// Returns UUID based on hashing of namespace UUID and name. -func newFromHash(h hash.Hash, ns UUID, name string) UUID { - u := UUID{} - h.Write(ns[:]) - h.Write([]byte(name)) - copy(u[:], h.Sum(nil)) - - return u -} diff --git a/vendor/github.com/satori/go.uuid/sql.go b/vendor/github.com/satori/go.uuid/sql.go deleted file mode 100644 index 56759d390..000000000 --- a/vendor/github.com/satori/go.uuid/sql.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2013-2018 by Maxim Bublis -// -// 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. - -package uuid - -import ( - "database/sql/driver" - "fmt" -) - -// Value implements the driver.Valuer interface. -func (u UUID) Value() (driver.Value, error) { - return u.String(), nil -} - -// Scan implements the sql.Scanner interface. -// A 16-byte slice is handled by UnmarshalBinary, while -// a longer byte slice or a string is handled by UnmarshalText. -func (u *UUID) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - if len(src) == Size { - return u.UnmarshalBinary(src) - } - return u.UnmarshalText(src) - - case string: - return u.UnmarshalText([]byte(src)) - } - - return fmt.Errorf("uuid: cannot convert %T to UUID", src) -} - -// NullUUID can be used with the standard sql package to represent a -// UUID value that can be NULL in the database -type NullUUID struct { - UUID UUID - Valid bool -} - -// Value implements the driver.Valuer interface. -func (u NullUUID) Value() (driver.Value, error) { - if !u.Valid { - return nil, nil - } - // Delegate to UUID Value function - return u.UUID.Value() -} - -// Scan implements the sql.Scanner interface. -func (u *NullUUID) Scan(src interface{}) error { - if src == nil { - u.UUID, u.Valid = Nil, false - return nil - } - - // Delegate to UUID Scan function - u.Valid = true - return u.UUID.Scan(src) -} diff --git a/vendor/github.com/satori/go.uuid/uuid.go b/vendor/github.com/satori/go.uuid/uuid.go deleted file mode 100644 index a2b8e2ca2..000000000 --- a/vendor/github.com/satori/go.uuid/uuid.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2013-2018 by Maxim Bublis -// -// 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. - -// Package uuid provides implementation of Universally Unique Identifier (UUID). -// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and -// version 2 (as specified in DCE 1.1). -package uuid - -import ( - "bytes" - "encoding/hex" -) - -// Size of a UUID in bytes. -const Size = 16 - -// UUID representation compliant with specification -// described in RFC 4122. -type UUID [Size]byte - -// UUID versions -const ( - _ byte = iota - V1 - V2 - V3 - V4 - V5 -) - -// UUID layout variants. -const ( - VariantNCS byte = iota - VariantRFC4122 - VariantMicrosoft - VariantFuture -) - -// UUID DCE domains. -const ( - DomainPerson = iota - DomainGroup - DomainOrg -) - -// String parse helpers. -var ( - urnPrefix = []byte("urn:uuid:") - byteGroups = []int{8, 4, 4, 4, 12} -) - -// Nil is special form of UUID that is specified to have all -// 128 bits set to zero. -var Nil = UUID{} - -// Predefined namespace UUIDs. -var ( - NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) - NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) - NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) - NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) -) - -// Equal returns true if u1 and u2 equals, otherwise returns false. -func Equal(u1 UUID, u2 UUID) bool { - return bytes.Equal(u1[:], u2[:]) -} - -// Version returns algorithm version used to generate UUID. -func (u UUID) Version() byte { - return u[6] >> 4 -} - -// Variant returns UUID layout variant. -func (u UUID) Variant() byte { - switch { - case (u[8] >> 7) == 0x00: - return VariantNCS - case (u[8] >> 6) == 0x02: - return VariantRFC4122 - case (u[8] >> 5) == 0x06: - return VariantMicrosoft - case (u[8] >> 5) == 0x07: - fallthrough - default: - return VariantFuture - } -} - -// Bytes returns bytes slice representation of UUID. -func (u UUID) Bytes() []byte { - return u[:] -} - -// Returns canonical string representation of UUID: -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. -func (u UUID) String() string { - buf := make([]byte, 36) - - hex.Encode(buf[0:8], u[0:4]) - buf[8] = '-' - hex.Encode(buf[9:13], u[4:6]) - buf[13] = '-' - hex.Encode(buf[14:18], u[6:8]) - buf[18] = '-' - hex.Encode(buf[19:23], u[8:10]) - buf[23] = '-' - hex.Encode(buf[24:], u[10:]) - - return string(buf) -} - -// SetVersion sets version bits. -func (u *UUID) SetVersion(v byte) { - u[6] = (u[6] & 0x0f) | (v << 4) -} - -// SetVariant sets variant bits. -func (u *UUID) SetVariant(v byte) { - switch v { - case VariantNCS: - u[8] = (u[8]&(0xff>>1) | (0x00 << 7)) - case VariantRFC4122: - u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) - case VariantMicrosoft: - u[8] = (u[8]&(0xff>>3) | (0x06 << 5)) - case VariantFuture: - fallthrough - default: - u[8] = (u[8]&(0xff>>3) | (0x07 << 5)) - } -} - -// Must is a helper that wraps a call to a function returning (UUID, error) -// and panics if the error is non-nil. It is intended for use in variable -// initializations such as -// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")); -func Must(u UUID, err error) UUID { - if err != nil { - panic(err) - } - return u -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 820e51365..79fb23f7e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -298,7 +298,7 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value -# github.com/google/uuid v1.3.1 +# github.com/google/uuid v1.6.0 ## explicit github.com/google/uuid # github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 @@ -621,9 +621,6 @@ github.com/sashamelentyev/interfacebloat/pkg/analyzer ## explicit; go 1.19 github.com/sashamelentyev/usestdlibvars/pkg/analyzer github.com/sashamelentyev/usestdlibvars/pkg/analyzer/internal/mapping -# github.com/satori/go.uuid v1.2.0 -## explicit -github.com/satori/go.uuid # github.com/securego/gosec/v2 v2.15.0 ## explicit; go 1.19 github.com/securego/gosec/v2 From 37c922cada5dcaed4aba5a0a7c670d0bb040dede Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 22:40:43 +0200 Subject: [PATCH 03/31] Switch to github.com/google/uuid --- http/jsonapi/runtime/value_sanitizers.go | 4 ++-- maintenance/errors/bricks.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/http/jsonapi/runtime/value_sanitizers.go b/http/jsonapi/runtime/value_sanitizers.go index 1eba98afe..7246d5617 100644 --- a/http/jsonapi/runtime/value_sanitizers.go +++ b/http/jsonapi/runtime/value_sanitizers.go @@ -8,7 +8,7 @@ import ( "fmt" "strconv" - uuid "github.com/satori/go.uuid" + uuid "github.com/google/uuid" "github.com/shopspring/decimal" "github.com/pace/bricks/pkg/isotime" @@ -56,7 +56,7 @@ func (n noopSanitizer) SanitizeValue(fieldName string, value string) (interface{ type uuidSanitizer struct{} func (u uuidSanitizer) SanitizeValue(fieldName string, value string) (interface{}, error) { - if _, err := uuid.FromString(value); err != nil { + if _, err := uuid.Parse(value); err != nil { return nil, err } return value, nil diff --git a/maintenance/errors/bricks.go b/maintenance/errors/bricks.go index e223dbda8..47f1f0ed2 100644 --- a/maintenance/errors/bricks.go +++ b/maintenance/errors/bricks.go @@ -8,7 +8,7 @@ package errors import ( "strconv" - uuid "github.com/satori/go.uuid" + uuid "github.com/google/uuid" "github.com/pace/bricks/http/jsonapi/runtime" ) @@ -62,7 +62,7 @@ func (e *BricksError) Status() int { // with a JSON error object func (e *BricksError) AsRuntimeError() *runtime.Error { j := &runtime.Error{ - ID: uuid.NewV4().String(), + ID: uuid.NewString(), Status: strconv.Itoa(e.status), Code: e.code, Title: e.title, From e5c68e40eb7b95abc0d8354629671edd38aa70f7 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 22:51:39 +0200 Subject: [PATCH 04/31] gomod: Update github.com/PuerkitoBio/rehttp to v1.4.0 --- go.mod | 2 +- go.sum | 4 +- .../github.com/PuerkitoBio/rehttp/.travis.yml | 11 -- .../github.com/PuerkitoBio/rehttp/README.md | 2 +- .../PuerkitoBio/rehttp/cancelreader.go | 36 ++++++ .../PuerkitoBio/rehttp/context_post17.go | 1 + .../PuerkitoBio/rehttp/context_pre17.go | 1 + .../rehttp/perattempttimeout_post17.go | 19 ++++ .../rehttp/perattempttimeout_pre17.go | 19 ++++ .../github.com/PuerkitoBio/rehttp/rehttp.go | 106 +++++++++++++----- .../PuerkitoBio/rehttp/timeouterr_post113.go | 18 +++ .../PuerkitoBio/rehttp/timeouterr_pre113.go | 15 +++ vendor/modules.txt | 2 +- 13 files changed, 195 insertions(+), 41 deletions(-) delete mode 100644 vendor/github.com/PuerkitoBio/rehttp/.travis.yml create mode 100644 vendor/github.com/PuerkitoBio/rehttp/cancelreader.go create mode 100644 vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_post17.go create mode 100644 vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_pre17.go create mode 100644 vendor/github.com/PuerkitoBio/rehttp/timeouterr_post113.go create mode 100644 vendor/github.com/PuerkitoBio/rehttp/timeouterr_pre113.go diff --git a/go.mod b/go.mod index da159f9b5..0076efeca 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 replace github.com/asaskevich/govalidator => github.com/pieceofsoul/govalidator v0.0.0-20230607103513-8dce951b10b8 require ( - github.com/PuerkitoBio/rehttp v1.1.0 + github.com/PuerkitoBio/rehttp v1.4.0 github.com/adjust/rmq/v3 v3.0.0 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/bsm/redislock v0.5.0 diff --git a/go.sum b/go.sum index 7e809a2f7..050c0adc9 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/OpenPeeDeeP/depguard v1.1.1 h1:TSUznLjvp/4IUP+OQ0t/4jF4QUyxIcVX8YnghZdunyA= github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= -github.com/PuerkitoBio/rehttp v1.1.0 h1:JFZ7OeK+hbJpTxhNB0NDZT47AuXqCU0Smxfjtph7/Rs= -github.com/PuerkitoBio/rehttp v1.1.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= +github.com/PuerkitoBio/rehttp v1.4.0 h1:rIN7A2s+O9fmHUM1vUcInvlHj9Ysql4hE+Y0wcl/xk8= +github.com/PuerkitoBio/rehttp v1.4.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= github.com/adjust/rmq/v3 v3.0.0 h1:+tfWjcbcK+O09WTEa/wzmxmGuvC0FgtKCbNKjI8aXmY= github.com/adjust/rmq/v3 v3.0.0/go.mod h1:rji/DBwOpm3DfRfSYS/w8IrVRMz9+P+ffm4nQXPC0Bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= diff --git a/vendor/github.com/PuerkitoBio/rehttp/.travis.yml b/vendor/github.com/PuerkitoBio/rehttp/.travis.yml deleted file mode 100644 index 7e1d84eab..000000000 --- a/vendor/github.com/PuerkitoBio/rehttp/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - 1.7.x - - 1.8.x - - 1.9.x - - "1.10.x" - - "1.11.x" - - "1.12.x" - - tip - diff --git a/vendor/github.com/PuerkitoBio/rehttp/README.md b/vendor/github.com/PuerkitoBio/rehttp/README.md index 2e9d64eb9..1c730fdfb 100644 --- a/vendor/github.com/PuerkitoBio/rehttp/README.md +++ b/vendor/github.com/PuerkitoBio/rehttp/README.md @@ -1,4 +1,4 @@ -# rehttp [![build status](https://secure.travis-ci.org/PuerkitoBio/rehttp.png)](http://travis-ci.org/PuerkitoBio/rehttp) [![Go Reference](https://pkg.go.dev/badge/rehttp.svg)](https://pkg.go.dev/rehttp) +# rehttp [![Build Status](https://github.com/PuerkitoBio/rehttp/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/PuerkitoBio/rehttp/actions) [![Go Reference](https://pkg.go.dev/badge/github.com/PuerkitoBio/rehttp.svg)](https://pkg.go.dev/github.com/PuerkitoBio/rehttp) Package rehttp implements an HTTP Transport (an `http.RoundTripper`) that handles retries. See the [godoc][] for details. diff --git a/vendor/github.com/PuerkitoBio/rehttp/cancelreader.go b/vendor/github.com/PuerkitoBio/rehttp/cancelreader.go new file mode 100644 index 000000000..13f794c00 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/rehttp/cancelreader.go @@ -0,0 +1,36 @@ +package rehttp + +import ( + "context" + "io" + "net/http" +) + +type cancelReader struct { + io.ReadCloser + + cancel context.CancelFunc +} + +func (r cancelReader) Close() error { + r.cancel() + return r.ReadCloser.Close() +} + +// injectCancelReader propagates the ability for the caller to cancel the request context +// once done with the response. If the transport cancels before the body stream is read, +// a race begins where the caller may be unable to read the response bytes before the stream +// is closed and an error is returned. This helper function wraps a response body in a +// io.ReadCloser that cancels the context once the body is closed, preventing a context leak. +// Solution based on https://github.com/go-kit/kit/issues/773. +func injectCancelReader(res *http.Response, cancel context.CancelFunc) *http.Response { + if res == nil { + return nil + } + + res.Body = cancelReader{ + ReadCloser: res.Body, + cancel: cancel, + } + return res +} diff --git a/vendor/github.com/PuerkitoBio/rehttp/context_post17.go b/vendor/github.com/PuerkitoBio/rehttp/context_post17.go index e4c27a29f..dc5eb1c02 100644 --- a/vendor/github.com/PuerkitoBio/rehttp/context_post17.go +++ b/vendor/github.com/PuerkitoBio/rehttp/context_post17.go @@ -1,3 +1,4 @@ +//go:build go1.7 // +build go1.7 package rehttp diff --git a/vendor/github.com/PuerkitoBio/rehttp/context_pre17.go b/vendor/github.com/PuerkitoBio/rehttp/context_pre17.go index e4aa70d44..41ca441f7 100644 --- a/vendor/github.com/PuerkitoBio/rehttp/context_pre17.go +++ b/vendor/github.com/PuerkitoBio/rehttp/context_pre17.go @@ -1,3 +1,4 @@ +//go:build !go1.7 // +build !go1.7 package rehttp diff --git a/vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_post17.go b/vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_post17.go new file mode 100644 index 000000000..e92c34979 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_post17.go @@ -0,0 +1,19 @@ +//go:build go1.7 +// +build go1.7 + +package rehttp + +import ( + "context" + "net/http" + "time" +) + +func getRequestContext(req *http.Request) context.Context { + return req.Context() +} + +func getPerAttemptTimeoutInfo(ctx context.Context, req *http.Request, timeout time.Duration) (*http.Request, context.CancelFunc) { + tctx, cancel := context.WithTimeout(ctx, timeout) + return req.WithContext(tctx), cancel +} diff --git a/vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_pre17.go b/vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_pre17.go new file mode 100644 index 000000000..e44e4e5ea --- /dev/null +++ b/vendor/github.com/PuerkitoBio/rehttp/perattempttimeout_pre17.go @@ -0,0 +1,19 @@ +//go:build !go1.7 +// +build !go1.7 + +package rehttp + +import ( + "context" + "net/http" + "time" +) + +func getRequestContext(req *http.Request) context.Context { + return nil // req.Context() doesn't exist before 1.7 +} + +func getPerAttemptTimeoutInfo(ctx context.Context, req *http.Request, timeout time.Duration) (*http.Request, context.CancelFunc) { + // req.WithContext() doesn't exist before 1.7, so noop + return req, func() {} +} diff --git a/vendor/github.com/PuerkitoBio/rehttp/rehttp.go b/vendor/github.com/PuerkitoBio/rehttp/rehttp.go index 0879e5de9..394be84c1 100644 --- a/vendor/github.com/PuerkitoBio/rehttp/rehttp.go +++ b/vendor/github.com/PuerkitoBio/rehttp/rehttp.go @@ -9,16 +9,18 @@ // // The package offers common delay strategies as ready-made functions that // return a DelayFn: -// - ConstDelay(delay time.Duration) DelayFn -// - ExpJitterDelay(base, max time.Duration) DelayFn +// - ConstDelay(delay time.Duration) DelayFn +// - ExpJitterDelay(base, max time.Duration) DelayFn +// - ExpJitterDelayWithRand(base, max time.Duration, generator func(int64) int64) DelayFn // // It also provides common retry helpers that return a RetryFn: -// - RetryIsErr(func(error) bool) RetryFn -// - RetryHTTPMethods(methods ...string) RetryFn -// - RetryMaxRetries(max int) RetryFn -// - RetryStatuses(statuses ...int) RetryFn -// - RetryStatusInterval(fromStatus, toStatus int) RetryFn -// - RetryTemporaryErr() RetryFn +// - RetryIsErr(func(error) bool) RetryFn +// - RetryHTTPMethods(methods ...string) RetryFn +// - RetryMaxRetries(max int) RetryFn +// - RetryStatuses(statuses ...int) RetryFn +// - RetryStatusInterval(fromStatus, toStatus int) RetryFn +// - RetryTimeoutErr() RetryFn +// - RetryTemporaryErr() RetryFn // // Those can be combined with RetryAny or RetryAll as needed. RetryAny // enables retries if any of the RetryFn return true, while RetryAll @@ -38,17 +40,18 @@ // (https://golang.org/pkg/net/http/#Transport.CancelRequest). // // On Go1.7+, it uses the context returned by http.Request.Context -// to check for cancelled requests. +// to check for cancelled requests. Before Go1.7, PerAttemptTimeout +// has no effect. // // It should work on Go1.5, but only if there is no timeout set on the // *http.Client. Go's stdlib will return an error on the first request // if that's the case, because it requires a RoundTripper that // implements the CancelRequest method. -// package rehttp import ( "bytes" + "context" "errors" "io" "io/ioutil" @@ -62,6 +65,11 @@ import ( // PRNG is the *math.Rand value to use to add jitter to the backoff // algorithm used in ExpJitterDelay. By default it uses a *rand.Rand // initialized with a source based on the current time in nanoseconds. +// +// Deprecated: math/rand sources can panic if used concurrently without +// synchronization. PRNG is no longer used by this package and its use +// outside this package is discouraged. +// https://github.com/PuerkitoBio/rehttp/issues/12 var PRNG = rand.New(rand.NewSource(time.Now().UnixNano())) // terribly named interface to detect errors that support Temporary. @@ -173,6 +181,8 @@ func RetryIsErr(fn func(error) bool) RetryFn { // is a temporary error. A temporary error is one that implements // the Temporary() bool method. Most errors from the net package implement // this. +// This interface was deprecated in go 1.18. Favor RetryTimeoutErr. +// https://github.com/golang/go/issues/45729 func RetryTemporaryErr() RetryFn { return RetryIsErr(func(err error) bool { if terr, ok := err.(temporaryer); ok { @@ -182,6 +192,16 @@ func RetryTemporaryErr() RetryFn { }) } +// RetryTimeoutErr returns a RetryFn that retries if the Attempt's error +// is a timeout error. Before go 1.13, a timeout error is one that implements +// the Timeout() bool method. Most errors from the net package implement this. +// After go 1.13, a timeout error is one that implements the net.Error interface +// which includes both Timeout() and Temporary() to make it less likely to +// falsely identify errors that occurred outside of the net package. +func RetryTimeoutErr() RetryFn { + return RetryIsErr(isTimeoutErr) +} + // RetryStatusInterval returns a RetryFn that retries if the response's // status code is in the provided half-closed interval [fromStatus, toStatus) // (that is, it retries if fromStatus <= Response.StatusCode < toStatus, so @@ -213,7 +233,7 @@ func RetryStatuses(statuses ...int) RetryFn { // RetryHTTPMethods returns a RetryFn that retries if the request's // HTTP method is one of the provided methods. It is meant to be used -// in conjunction with another RetryFn such as RetryTemporaryErr combined +// in conjunction with another RetryFn such as RetryTimeoutErr combined // using RetryAll, otherwise this function will retry any successful // request made with one of the provided methods. func RetryHTTPMethods(methods ...string) RetryFn { @@ -239,18 +259,29 @@ func ConstDelay(delay time.Duration) DelayFn { } } -// ExpJitterDelay returns a DelayFn that returns a delay between 0 and -// base * 2^attempt capped at max (an exponential backoff delay with -// jitter). +// ExpJitterDelay is identical to [ExpJitterDelayWithRand], using +// math/rand.Int63n as the random generator function. +// This package does not call [rand.Seed], so it is the caller's +// responsibility to ensure the default generator is properly seeded. +func ExpJitterDelay(base, max time.Duration) DelayFn { + return ExpJitterDelayWithRand(base, max, rand.Int63n) +} + +// ExpJitterDelayWithRand returns a DelayFn that returns a delay +// between 0 and base * 2^attempt capped at max (an exponential +// backoff delay with jitter). The generator argument is expected +// to generate a random int64 in the half open interval [0, n). +// It is the caller's responsibility to ensure that the function is +// safe for concurrent use. // // See the full jitter algorithm in: // http://www.awsarchitectureblog.com/2015/03/backoff.html -func ExpJitterDelay(base, max time.Duration) DelayFn { +func ExpJitterDelayWithRand(base, max time.Duration, generator func(n int64) int64) DelayFn { return func(attempt Attempt) time.Duration { exp := math.Pow(2, float64(attempt.Index)) top := float64(base) * exp return time.Duration( - PRNG.Int63n(int64(math.Min(float64(max), top))), + generator(int64(math.Min(float64(max), top))), ) } } @@ -267,6 +298,22 @@ type Transport struct { // is non-nil. PreventRetryWithBody bool + // PerAttemptTimeout can be optionally set to add per-attempt timeouts. + // These may be used in place of or in conjunction with overall timeouts. + // For example, a per-attempt timeout of 5s would mean an attempt will + // be canceled after 5s, then the delay fn will be consulted before + // potentially making another attempt, which will again be capped at 5s. + // This means that the overall duration may be up to + // (PerAttemptTimeout + delay) * n, where n is the maximum attempts. + // If using an overall timeout (whether on the http client or the request + // context), the request will stop at whichever timeout is reached first. + // Your RetryFn can determine if a request hit the per-attempt timeout by + // checking if attempt.Error == context.DeadlineExceeded (or use errors.Is + // on go 1.13+). + // time.Duration(0) signals that no per-attempt timeout should be used. + // Note that before go 1.7 this option has no effect. + PerAttemptTimeout time.Duration + // retry is a function that determines if the request should be retried. // Unless a retry is prevented based on PreventRetryWithBody, all requests // go through that function, even those that are typically considered @@ -282,7 +329,10 @@ type Transport struct { // adds retry logic as per its configuration. func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { var attempt int - preventRetry := req.Body != nil && t.PreventRetryWithBody + preventRetry := req.Body != nil && req.Body != http.NoBody && t.PreventRetryWithBody + + // used as a baseline to set fresh timeouts per-attempt if needed + ctx := getRequestContext(req) // get the done cancellation channel for the context, will be nil // for < go1.7. @@ -290,7 +340,7 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { // buffer the body if needed var br *bytes.Reader - if req.Body != nil && !preventRetry { + if req.Body != nil && req.Body != http.NoBody && !preventRetry { var buf bytes.Buffer if _, err := io.Copy(&buf, req.Body); err != nil { // cannot even try the first attempt, body has been consumed @@ -304,19 +354,24 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { } for { - res, err := t.RoundTripper.RoundTrip(req) + var cancel context.CancelFunc = func() {} // empty unless a timeout is set + reqWithTimeout := req + if t.PerAttemptTimeout != 0 { + reqWithTimeout, cancel = getPerAttemptTimeoutInfo(ctx, req, t.PerAttemptTimeout) + } + res, err := t.RoundTripper.RoundTrip(reqWithTimeout) if preventRetry { - return res, err + return injectCancelReader(res, cancel), err } retry, delay := t.retry(Attempt{ - Request: req, + Request: reqWithTimeout, Response: res, Index: attempt, Error: err, }) if !retry { - return res, err + return injectCancelReader(res, cancel), err } if br != nil { @@ -325,15 +380,16 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { // to reset on the request is the body, if any. if _, serr := br.Seek(0, 0); serr != nil { // failed to retry, return the results - return res, err + return injectCancelReader(res, cancel), err } - req.Body = ioutil.NopCloser(br) + reqWithTimeout.Body = ioutil.NopCloser(br) } // close the disposed response's body, if any if res != nil { - io.Copy(ioutil.Discard, res.Body) + _, _ = io.Copy(ioutil.Discard, res.Body) res.Body.Close() } + cancel() // we're done with this response and won't be returning it, so it's safe to cancel immediately select { case <-time.After(delay): diff --git a/vendor/github.com/PuerkitoBio/rehttp/timeouterr_post113.go b/vendor/github.com/PuerkitoBio/rehttp/timeouterr_post113.go new file mode 100644 index 000000000..4143d7c73 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/rehttp/timeouterr_post113.go @@ -0,0 +1,18 @@ +//go:build go1.13 +// +build go1.13 + +package rehttp + +import ( + "errors" + "net" +) + +func isTimeoutErr(err error) bool { + var neterr net.Error + if errors.As(err, &neterr) && neterr.Timeout() { + return true + } + + return false +} diff --git a/vendor/github.com/PuerkitoBio/rehttp/timeouterr_pre113.go b/vendor/github.com/PuerkitoBio/rehttp/timeouterr_pre113.go new file mode 100644 index 000000000..4517e44e1 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/rehttp/timeouterr_pre113.go @@ -0,0 +1,15 @@ +//go:build !go1.13 +// +build !go1.13 + +package rehttp + +type timeouter interface { + Timeout() bool +} + +func isTimeoutErr(err error) bool { + if terr, ok := err.(timeouter); ok { + return terr.Timeout() + } + return false +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 79fb23f7e..c676ea9c2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -29,7 +29,7 @@ github.com/Masterminds/semver # github.com/OpenPeeDeeP/depguard v1.1.1 ## explicit; go 1.13 github.com/OpenPeeDeeP/depguard -# github.com/PuerkitoBio/rehttp v1.1.0 +# github.com/PuerkitoBio/rehttp v1.4.0 ## explicit; go 1.16 github.com/PuerkitoBio/rehttp # github.com/adjust/rmq/v3 v3.0.0 From 7ff9751bc4f6e4ef43b70b43c44ed9a692866353 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:01:43 +0200 Subject: [PATCH 05/31] gomod: Update github.com/caarlos0/env to v10 --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/caarlos0/env/.gitignore | 1 - vendor/github.com/caarlos0/env/.hound.yml | 2 - vendor/github.com/caarlos0/env/.travis.yml | 16 - vendor/github.com/caarlos0/env/README.md | 115 ---- vendor/github.com/caarlos0/env/env.go | 390 ----------- vendor/github.com/caarlos0/env/v10/.gitignore | 4 + .../github.com/caarlos0/env/v10/.golangci.yml | 8 + .../caarlos0/env/v10/.goreleaser.yml | 3 + vendor/github.com/caarlos0/env/v10/.mailmap | 7 + .../caarlos0/env/{ => v10}/LICENSE.md | 2 +- vendor/github.com/caarlos0/env/v10/Makefile | 37 ++ vendor/github.com/caarlos0/env/v10/README.md | 610 +++++++++++++++++ vendor/github.com/caarlos0/env/v10/env.go | 614 ++++++++++++++++++ .../github.com/caarlos0/env/v10/env_tomap.go | 16 + .../caarlos0/env/v10/env_tomap_windows.go | 29 + vendor/github.com/caarlos0/env/v10/error.go | 164 +++++ vendor/modules.txt | 6 +- 19 files changed, 1499 insertions(+), 531 deletions(-) delete mode 100644 vendor/github.com/caarlos0/env/.gitignore delete mode 100644 vendor/github.com/caarlos0/env/.hound.yml delete mode 100644 vendor/github.com/caarlos0/env/.travis.yml delete mode 100644 vendor/github.com/caarlos0/env/README.md delete mode 100644 vendor/github.com/caarlos0/env/env.go create mode 100644 vendor/github.com/caarlos0/env/v10/.gitignore create mode 100644 vendor/github.com/caarlos0/env/v10/.golangci.yml create mode 100644 vendor/github.com/caarlos0/env/v10/.goreleaser.yml create mode 100644 vendor/github.com/caarlos0/env/v10/.mailmap rename vendor/github.com/caarlos0/env/{ => v10}/LICENSE.md (95%) create mode 100644 vendor/github.com/caarlos0/env/v10/Makefile create mode 100644 vendor/github.com/caarlos0/env/v10/README.md create mode 100644 vendor/github.com/caarlos0/env/v10/env.go create mode 100644 vendor/github.com/caarlos0/env/v10/env_tomap.go create mode 100644 vendor/github.com/caarlos0/env/v10/env_tomap_windows.go create mode 100644 vendor/github.com/caarlos0/env/v10/error.go diff --git a/go.mod b/go.mod index 0076efeca..16fa86761 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/adjust/rmq/v3 v3.0.0 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/bsm/redislock v0.5.0 - github.com/caarlos0/env v3.3.0+incompatible + github.com/caarlos0/env/v10 v10.0.0 github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 github.com/dave/jennifer v1.0.2 github.com/getkin/kin-openapi v0.0.0-20180813063848-e1956e8013e5 diff --git a/go.sum b/go.sum index 050c0adc9..f4533371c 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/bsm/redislock v0.5.0 h1:ODM11/cbuUXQqLgZWK6XQnufaTjsBE2UcwBc2EAFNDA= github.com/bsm/redislock v0.5.0/go.mod h1:qagqKlV+xiLy26iV34Y3zRPxRcJjQYbV7pZfWFeSZ8M= github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= -github.com/caarlos0/env v3.3.0+incompatible h1:jCfY0ilpzC2FFViyZyDKCxKybDESTwaR+ebh8zm6AOE= -github.com/caarlos0/env v3.3.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= +github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= +github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg= github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= diff --git a/vendor/github.com/caarlos0/env/.gitignore b/vendor/github.com/caarlos0/env/.gitignore deleted file mode 100644 index 2d830686d..000000000 --- a/vendor/github.com/caarlos0/env/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coverage.out diff --git a/vendor/github.com/caarlos0/env/.hound.yml b/vendor/github.com/caarlos0/env/.hound.yml deleted file mode 100644 index e5c719dd2..000000000 --- a/vendor/github.com/caarlos0/env/.hound.yml +++ /dev/null @@ -1,2 +0,0 @@ -go: - enabled: true diff --git a/vendor/github.com/caarlos0/env/.travis.yml b/vendor/github.com/caarlos0/env/.travis.yml deleted file mode 100644 index 4ad7e69f3..000000000 --- a/vendor/github.com/caarlos0/env/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go -go: - - 1.5 - - 1.6 - - 1.7 - - 1.8 - - tip -before_install: - - go get github.com/axw/gocov/gocov - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - go test -v -cover -race -coverprofile=coverage.out -after_script: - - go get github.com/mattn/goveralls - - goveralls -coverprofile=coverage.out -service=travis-ci -repotoken='eCcizKmTdSaJCz8Ih33WDppdqb9kioYwi' diff --git a/vendor/github.com/caarlos0/env/README.md b/vendor/github.com/caarlos0/env/README.md deleted file mode 100644 index cf46c544b..000000000 --- a/vendor/github.com/caarlos0/env/README.md +++ /dev/null @@ -1,115 +0,0 @@ -# env [![Build Status](https://travis-ci.org/caarlos0/env.svg?branch=master)](https://travis-ci.org/caarlos0/env) [![Coverage Status](https://coveralls.io/repos/caarlos0/env/badge.svg?branch=master&service=github)](https://coveralls.io/github/caarlos0/env?branch=master) [![](https://godoc.org/github.com/caarlos0/env?status.svg)](http://godoc.org/github.com/caarlos0/env) [![](http://goreportcard.com/badge/caarlos0/env)](http://goreportcard.com/report/caarlos0/env) [![SayThanks.io](https://img.shields.io/badge/SayThanks.io-%E2%98%BC-1EAEDB.svg?style=flat-square)](https://saythanks.io/to/caarlos0) - -A KISS way to deal with environment variables in Go. - -## Why - -At first, it was boring for me to write down an entire function just to -get some `var` from the environment and default to another in case it's missing. - -For that manner, I wrote a `GetOr` function in the -[go-idioms](https://github.com/caarlos0/go-idioms) project. - -Then, I got pissed about writing `os.Getenv`, `os.Setenv`, `os.Unsetenv`... -it kind of make more sense to me write it as `env.Get`, `env.Set`, `env.Unset`. -So I did. - -Then I got a better idea: to use `struct` tags to do all that work for me. - -## Example - -A very basic example (check the `examples` folder): - -```go -package main - -import ( - "fmt" - "time" - - "github.com/caarlos0/env" -) - -type config struct { - Home string `env:"HOME"` - Port int `env:"PORT" envDefault:"3000"` - IsProduction bool `env:"PRODUCTION"` - Hosts []string `env:"HOSTS" envSeparator:":"` - Duration time.Duration `env:"DURATION"` -} - -func main() { - cfg := config{} - err := env.Parse(&cfg) - if err != nil { - fmt.Printf("%+v\n", err) - } - fmt.Printf("%+v\n", cfg) -} -``` - -You can run it like this: - -```sh -$ PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s go run examples/first.go -{Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s} -``` - -## Supported types and defaults - -The library has built-in support for the following types: - -* `string` -* `int` -* `uint` -* `int64` -* `bool` -* `float32` -* `float64` -* `time.Duration` -* `[]string` -* `[]int` -* `[]bool` -* `[]float32` -* `[]float64` -* `[]time.Duration` -* .. or use/define a [custom parser func](#custom-parser-funcs) for any other type - -If you set the `envDefault` tag for something, this value will be used in the -case of absence of it in the environment. If you don't do that AND the -environment variable is also not set, the zero-value -of the type will be used: empty for `string`s, `false` for `bool`s -and `0` for `int`s. - -By default, slice types will split the environment value on `,`; you can change this behavior by setting the `envSeparator` tag. - -## Custom Parser Funcs - -If you have a type that is not supported out of the box by the lib, you are able -to use (or define) and pass custom parsers (and their associated `reflect.Type`) to the -`env.ParseWithFuncs()` function. - -In addition to accepting a struct pointer (same as `Parse()`), this function also -accepts a `env.CustomParsers` arg that under the covers is a `map[reflect.Type]env.ParserFunc`. - -To see what this looks like in practice, take a look at the [commented block in the example](https://github.com/caarlos0/env/blob/master/examples/first.go#L35-L39). - -`env` also ships with some pre-built custom parser funcs for common types. You -can check them out [here](parsers/). - -## Required fields - -The `env` tag option `required` (e.g., `env:"tagKey,required"`) can be added -to ensure that some environment variable is set. In the example above, -an error is returned if the `config` struct is changed to: - - -```go -type config struct { - Home string `env:"HOME"` - Port int `env:"PORT" envDefault:"3000"` - IsProduction bool `env:"PRODUCTION"` - Hosts []string `env:"HOSTS" envSeparator:":"` - SecretKey string `env:"SECRET_KEY,required"` -} -``` diff --git a/vendor/github.com/caarlos0/env/env.go b/vendor/github.com/caarlos0/env/env.go deleted file mode 100644 index 15f0e8117..000000000 --- a/vendor/github.com/caarlos0/env/env.go +++ /dev/null @@ -1,390 +0,0 @@ -package env - -import ( - "errors" - "fmt" - "os" - "reflect" - "strconv" - "strings" - "time" -) - -var ( - // ErrNotAStructPtr is returned if you pass something that is not a pointer to a - // Struct to Parse - ErrNotAStructPtr = errors.New("Expected a pointer to a Struct") - // ErrUnsupportedType if the struct field type is not supported by env - ErrUnsupportedType = errors.New("Type is not supported") - // ErrUnsupportedSliceType if the slice element type is not supported by env - ErrUnsupportedSliceType = errors.New("Unsupported slice type") - // Friendly names for reflect types - sliceOfInts = reflect.TypeOf([]int(nil)) - sliceOfInt64s = reflect.TypeOf([]int64(nil)) - sliceOfUint64s = reflect.TypeOf([]uint64(nil)) - sliceOfStrings = reflect.TypeOf([]string(nil)) - sliceOfBools = reflect.TypeOf([]bool(nil)) - sliceOfFloat32s = reflect.TypeOf([]float32(nil)) - sliceOfFloat64s = reflect.TypeOf([]float64(nil)) - sliceOfDurations = reflect.TypeOf([]time.Duration(nil)) -) - -// CustomParsers is a friendly name for the type that `ParseWithFuncs()` accepts -type CustomParsers map[reflect.Type]ParserFunc - -// ParserFunc defines the signature of a function that can be used within `CustomParsers` -type ParserFunc func(v string) (interface{}, error) - -// Parse parses a struct containing `env` tags and loads its values from -// environment variables. -func Parse(v interface{}) error { - ptrRef := reflect.ValueOf(v) - if ptrRef.Kind() != reflect.Ptr { - return ErrNotAStructPtr - } - ref := ptrRef.Elem() - if ref.Kind() != reflect.Struct { - return ErrNotAStructPtr - } - return doParse(ref, make(map[reflect.Type]ParserFunc, 0)) -} - -// ParseWithFuncs is the same as `Parse` except it also allows the user to pass -// in custom parsers. -func ParseWithFuncs(v interface{}, funcMap CustomParsers) error { - ptrRef := reflect.ValueOf(v) - if ptrRef.Kind() != reflect.Ptr { - return ErrNotAStructPtr - } - ref := ptrRef.Elem() - if ref.Kind() != reflect.Struct { - return ErrNotAStructPtr - } - return doParse(ref, funcMap) -} - -func doParse(ref reflect.Value, funcMap CustomParsers) error { - refType := ref.Type() - var errorList []string - - for i := 0; i < refType.NumField(); i++ { - if reflect.Ptr == ref.Field(i).Kind() && !ref.Field(i).IsNil() && ref.Field(i).CanSet() { - err := Parse(ref.Field(i).Interface()) - if nil != err { - return err - } - continue - } - value, err := get(refType.Field(i)) - if err != nil { - errorList = append(errorList, err.Error()) - continue - } - if value == "" { - continue - } - if err := set(ref.Field(i), refType.Field(i), value, funcMap); err != nil { - errorList = append(errorList, err.Error()) - continue - } - } - if len(errorList) == 0 { - return nil - } - return errors.New(strings.Join(errorList, ". ")) -} - -func get(field reflect.StructField) (string, error) { - var ( - val string - err error - ) - - key, opts := parseKeyForOption(field.Tag.Get("env")) - - defaultValue := field.Tag.Get("envDefault") - val = getOr(key, defaultValue) - - if len(opts) > 0 { - for _, opt := range opts { - // The only option supported is "required". - switch opt { - case "": - break - case "required": - val, err = getRequired(key) - default: - err = errors.New("Env tag option " + opt + " not supported.") - } - } - } - - return val, err -} - -// split the env tag's key into the expected key and desired option, if any. -func parseKeyForOption(key string) (string, []string) { - opts := strings.Split(key, ",") - return opts[0], opts[1:] -} - -func getRequired(key string) (string, error) { - if value, ok := os.LookupEnv(key); ok { - return value, nil - } - // We do not use fmt.Errorf to avoid another import. - return "", errors.New("Required environment variable " + key + " is not set") -} - -func getOr(key, defaultValue string) string { - value, ok := os.LookupEnv(key) - if ok { - return value - } - return defaultValue -} - -func set(field reflect.Value, refType reflect.StructField, value string, funcMap CustomParsers) error { - switch field.Kind() { - case reflect.Slice: - separator := refType.Tag.Get("envSeparator") - return handleSlice(field, value, separator) - case reflect.String: - field.SetString(value) - case reflect.Bool: - bvalue, err := strconv.ParseBool(value) - if err != nil { - return err - } - field.SetBool(bvalue) - case reflect.Int: - intValue, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return err - } - field.SetInt(intValue) - case reflect.Uint: - uintValue, err := strconv.ParseUint(value, 10, 32) - if err != nil { - return err - } - field.SetUint(uintValue) - case reflect.Float32: - v, err := strconv.ParseFloat(value, 32) - if err != nil { - return err - } - field.SetFloat(v) - case reflect.Float64: - v, err := strconv.ParseFloat(value, 64) - if err != nil { - return err - } - field.Set(reflect.ValueOf(v)) - case reflect.Int64: - if refType.Type.String() == "time.Duration" { - dValue, err := time.ParseDuration(value) - if err != nil { - return err - } - field.Set(reflect.ValueOf(dValue)) - } else { - intValue, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - field.SetInt(intValue) - } - case reflect.Uint64: - uintValue, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return err - } - field.SetUint(uintValue) - case reflect.Struct: - return handleStruct(field, refType, value, funcMap) - default: - parserFunc, ok := funcMap[refType.Type] - if !ok { - return ErrUnsupportedType - } - val, err := parserFunc(value) - if err != nil { - return err - } - field.Set(reflect.ValueOf(val)) - } - return nil -} - -func handleStruct(field reflect.Value, refType reflect.StructField, value string, funcMap CustomParsers) error { - // Does the custom parser func map contain this type? - parserFunc, ok := funcMap[field.Type()] - if !ok { - // Map does not contain a custom parser for this type - return ErrUnsupportedType - } - - // Call on the custom parser func - data, err := parserFunc(value) - if err != nil { - return fmt.Errorf("Custom parser error: %v", err) - } - - // Set the field to the data returned by the customer parser func - rv := reflect.ValueOf(data) - field.Set(rv) - - return nil -} - -func handleSlice(field reflect.Value, value, separator string) error { - if separator == "" { - separator = "," - } - - splitData := strings.Split(value, separator) - - switch field.Type() { - case sliceOfStrings: - field.Set(reflect.ValueOf(splitData)) - case sliceOfInts: - intData, err := parseInts(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(intData)) - case sliceOfInt64s: - int64Data, err := parseInt64s(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(int64Data)) - case sliceOfUint64s: - uint64Data, err := parseUint64s(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(uint64Data)) - case sliceOfFloat32s: - data, err := parseFloat32s(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(data)) - case sliceOfFloat64s: - data, err := parseFloat64s(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(data)) - case sliceOfBools: - boolData, err := parseBools(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(boolData)) - case sliceOfDurations: - durationData, err := parseDurations(splitData) - if err != nil { - return err - } - field.Set(reflect.ValueOf(durationData)) - default: - return ErrUnsupportedSliceType - } - return nil -} - -func parseInts(data []string) ([]int, error) { - intSlice := make([]int, 0, len(data)) - - for _, v := range data { - intValue, err := strconv.ParseInt(v, 10, 32) - if err != nil { - return nil, err - } - intSlice = append(intSlice, int(intValue)) - } - return intSlice, nil -} - -func parseInt64s(data []string) ([]int64, error) { - intSlice := make([]int64, 0, len(data)) - - for _, v := range data { - intValue, err := strconv.ParseInt(v, 10, 64) - if err != nil { - return nil, err - } - intSlice = append(intSlice, int64(intValue)) - } - return intSlice, nil -} - -func parseUint64s(data []string) ([]uint64, error) { - var uintSlice []uint64 - - for _, v := range data { - uintValue, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return nil, err - } - uintSlice = append(uintSlice, uint64(uintValue)) - } - return uintSlice, nil -} - -func parseFloat32s(data []string) ([]float32, error) { - float32Slice := make([]float32, 0, len(data)) - - for _, v := range data { - data, err := strconv.ParseFloat(v, 32) - if err != nil { - return nil, err - } - float32Slice = append(float32Slice, float32(data)) - } - return float32Slice, nil -} - -func parseFloat64s(data []string) ([]float64, error) { - float64Slice := make([]float64, 0, len(data)) - - for _, v := range data { - data, err := strconv.ParseFloat(v, 64) - if err != nil { - return nil, err - } - float64Slice = append(float64Slice, float64(data)) - } - return float64Slice, nil -} - -func parseBools(data []string) ([]bool, error) { - boolSlice := make([]bool, 0, len(data)) - - for _, v := range data { - bvalue, err := strconv.ParseBool(v) - if err != nil { - return nil, err - } - - boolSlice = append(boolSlice, bvalue) - } - return boolSlice, nil -} - -func parseDurations(data []string) ([]time.Duration, error) { - durationSlice := make([]time.Duration, 0, len(data)) - - for _, v := range data { - dvalue, err := time.ParseDuration(v) - if err != nil { - return nil, err - } - - durationSlice = append(durationSlice, dvalue) - } - return durationSlice, nil -} diff --git a/vendor/github.com/caarlos0/env/v10/.gitignore b/vendor/github.com/caarlos0/env/v10/.gitignore new file mode 100644 index 000000000..ca6a0ff8c --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/.gitignore @@ -0,0 +1,4 @@ +coverage.txt +bin +card.png +dist diff --git a/vendor/github.com/caarlos0/env/v10/.golangci.yml b/vendor/github.com/caarlos0/env/v10/.golangci.yml new file mode 100644 index 000000000..ff791f86e --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/.golangci.yml @@ -0,0 +1,8 @@ +linters: + enable: + - thelper + - gofumpt + - tparallel + - unconvert + - unparam + - wastedassign diff --git a/vendor/github.com/caarlos0/env/v10/.goreleaser.yml b/vendor/github.com/caarlos0/env/v10/.goreleaser.yml new file mode 100644 index 000000000..4688983c2 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/.goreleaser.yml @@ -0,0 +1,3 @@ +includes: + - from_url: + url: https://raw.githubusercontent.com/caarlos0/.goreleaserfiles/main/lib.yml diff --git a/vendor/github.com/caarlos0/env/v10/.mailmap b/vendor/github.com/caarlos0/env/v10/.mailmap new file mode 100644 index 000000000..eeeee6010 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/.mailmap @@ -0,0 +1,7 @@ +Carlos Alexandro Becker Carlos A Becker +Carlos Alexandro Becker Carlos A Becker +Carlos Alexandro Becker Carlos Alexandro Becker +Carlos Alexandro Becker Carlos Alexandro Becker +Carlos Alexandro Becker Carlos Becker +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> +actions-user github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/vendor/github.com/caarlos0/env/LICENSE.md b/vendor/github.com/caarlos0/env/v10/LICENSE.md similarity index 95% rename from vendor/github.com/caarlos0/env/LICENSE.md rename to vendor/github.com/caarlos0/env/v10/LICENSE.md index b7398672f..3a59b6b38 100644 --- a/vendor/github.com/caarlos0/env/LICENSE.md +++ b/vendor/github.com/caarlos0/env/v10/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-2016 Carlos Alexandro Becker +Copyright (c) 2015-2022 Carlos Alexandro Becker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/caarlos0/env/v10/Makefile b/vendor/github.com/caarlos0/env/v10/Makefile new file mode 100644 index 000000000..da8595fb9 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/Makefile @@ -0,0 +1,37 @@ +SOURCE_FILES?=./... +TEST_PATTERN?=. + +export GO111MODULE := on + +setup: + go mod tidy +.PHONY: setup + +build: + go build +.PHONY: build + +test: + go test -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=2m +.PHONY: test + +cover: test + go tool cover -html=coverage.txt +.PHONY: cover + +fmt: + gofumpt -w -l . +.PHONY: fmt + +lint: + golangci-lint run ./... +.PHONY: lint + +ci: build test +.PHONY: ci + +card: + wget -O card.png -c "https://og.caarlos0.dev/**env**: parse envs to structs.png?theme=light&md=1&fontSize=100px&images=https://github.com/caarlos0.png" +.PHONY: card + +.DEFAULT_GOAL := ci diff --git a/vendor/github.com/caarlos0/env/v10/README.md b/vendor/github.com/caarlos0/env/v10/README.md new file mode 100644 index 000000000..fcb6342f4 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/README.md @@ -0,0 +1,610 @@ +# env + +[![Build Status](https://img.shields.io/github/actions/workflow/status/caarlos0/env/build.yml?branch=main&style=for-the-badge)](https://github.com/caarlos0/env/actions?workflow=build) +[![Coverage Status](https://img.shields.io/codecov/c/gh/caarlos0/env.svg?logo=codecov&style=for-the-badge)](https://codecov.io/gh/caarlos0/env) +[![](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://pkg.go.dev/github.com/caarlos0/env/v10) + +A simple and zero-dependencies library to parse environment variables into +`struct`s. + +## Example + +Get the module with: + +```sh +go get github.com/caarlos0/env/v10 +``` + +The usage looks like this: + +```go +package main + +import ( + "fmt" + "time" + + "github.com/caarlos0/env/v10" +) + +type config struct { + Home string `env:"HOME"` + Port int `env:"PORT" envDefault:"3000"` + Password string `env:"PASSWORD,unset"` + IsProduction bool `env:"PRODUCTION"` + Duration time.Duration `env:"DURATION"` + Hosts []string `env:"HOSTS" envSeparator:":"` + TempFolder string `env:"TEMP_FOLDER,expand" envDefault:"${HOME}/tmp"` + StringInts map[string]int `env:"MAP_STRING_INT"` +} + +func main() { + cfg := config{} + if err := env.Parse(&cfg); err != nil { + fmt.Printf("%+v\n", err) + } + + fmt.Printf("%+v\n", cfg) +} +``` + +You can run it like this: + +```sh +$ PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s MAP_STRING_INT=k1:1,k2:2 go run main.go +{Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s StringInts:map[k1:1 k2:2]} +``` + +## Caveats + +> **Warning** +> +> **This is important!** + +- _Unexported fields_ are **ignored** + +## Supported types and defaults + +Out of the box all built-in types are supported, plus a few others that +are commonly used. + +Complete list: + +- `string` +- `bool` +- `int` +- `int8` +- `int16` +- `int32` +- `int64` +- `uint` +- `uint8` +- `uint16` +- `uint32` +- `uint64` +- `float32` +- `float64` +- `time.Duration` +- `encoding.TextUnmarshaler` +- `url.URL` + +Pointers, slices and slices of pointers, and maps of those types are also +supported. + +You can also use/define a [custom parser func](#custom-parser-funcs) for any +other type you want. + +You can also use custom keys and values in your maps, as long as you provide a +parser function for them. + +If you set the `envDefault` tag for something, this value will be used in the +case of absence of it in the environment. + +By default, slice types will split the environment value on `,`; you can change +this behavior by setting the `envSeparator` tag. For map types, the default +separator between key and value is `:` and `,` for key-value pairs. +The behavior can be changed by setting the `envKeyValSeparator` and +`envSeparator` tags accordingly. + +## Custom Parser Funcs + +If you have a type that is not supported out of the box by the lib, you are able +to use (or define) and pass custom parsers (and their associated `reflect.Type`) +to the `env.ParseWithOptions()` function. + +In addition to accepting a struct pointer (same as `Parse()`), this function +also accepts a `Options{}`, and you can set your custom parsers in the `FuncMap` +field. + +If you add a custom parser for, say `Foo`, it will also be used to parse +`*Foo` and `[]Foo` types. + +Check the examples in the [go doc](http://pkg.go.dev/github.com/caarlos0/env/v10) +for more info. + +### A note about `TextUnmarshaler` and `time.Time` + +Env supports by default anything that implements the `TextUnmarshaler` interface. +That includes things like `time.Time` for example. +The upside is that depending on the format you need, you don't need to change +anything. +The downside is that if you do need time in another format, you'll need to +create your own type. + +Its fairly straightforward: + +```go +type MyTime time.Time + +func (t *MyTime) UnmarshalText(text []byte) error { + tt, err := time.Parse("2006-01-02", string(text)) + *t = MyTime(tt) + return err +} + +type Config struct { + SomeTime MyTime `env:"SOME_TIME"` +} +``` + +And then you can parse `Config` with `env.Parse`. + +## Required fields + +The `env` tag option `required` (e.g., `env:"tagKey,required"`) can be added to +ensure that some environment variable is set. In the example above, an error is +returned if the `config` struct is changed to: + +```go +type config struct { + SecretKey string `env:"SECRET_KEY,required"` +} +``` + +> **Warning** +> +> Note that being set is not the same as being empty. +> If the variable is set, but empty, the field will have its type's default +> value. +> This also means that custom parser funcs will not be invoked. + +## Expand vars + +If you set the `expand` option, environment variables (either in `${var}` or +`$var` format) in the string will be replaced according with the actual value +of the variable. For example: + +```go +type config struct { + SecretKey string `env:"SECRET_KEY,expand"` +} +``` + +This also works with `envDefault`: + +```go +import ( + "fmt" + "github.com/caarlos0/env/v10" +) + +type config struct { + Host string `env:"HOST" envDefault:"localhost"` + Port int `env:"PORT" envDefault:"3000"` + Address string `env:"ADDRESS,expand" envDefault:"$HOST:${PORT}"` +} + +func main() { + cfg := config{} + if err := env.Parse(&cfg); err != nil { + fmt.Printf("%+v\n", err) + } + fmt.Printf("%+v\n", cfg) +} +``` + +results in this: + +```sh +$ PORT=8080 go run main.go +{Host:localhost Port:8080 Address:localhost:8080} +``` + +## Not Empty fields + +While `required` demands the environment variable to be set, it doesn't check +its value. If you want to make sure the environment is set and not empty, you +need to use the `notEmpty` tag option instead (`env:"SOME_ENV,notEmpty"`). + +Example: + +```go +type config struct { + SecretKey string `env:"SECRET_KEY,notEmpty"` +} +``` + +## Unset environment variable after reading it + +The `env` tag option `unset` (e.g., `env:"tagKey,unset"`) can be added +to ensure that some environment variable is unset after reading it. + +Example: + +```go +type config struct { + SecretKey string `env:"SECRET_KEY,unset"` +} +``` + +## From file + +The `env` tag option `file` (e.g., `env:"tagKey,file"`) can be added +in order to indicate that the value of the variable shall be loaded from a +file. +The path of that file is given by the environment variable associated with it: + +```go +package main + +import ( + "fmt" + "time" + + "github.com/caarlos0/env/v10" +) + +type config struct { + Secret string `env:"SECRET,file"` + Password string `env:"PASSWORD,file" envDefault:"/tmp/password"` + Certificate string `env:"CERTIFICATE,file,expand" envDefault:"${CERTIFICATE_FILE}"` +} + +func main() { + cfg := config{} + if err := env.Parse(&cfg); err != nil { + fmt.Printf("%+v\n", err) + } + + fmt.Printf("%+v\n", cfg) +} +``` + +```sh +$ echo qwerty > /tmp/secret +$ echo dvorak > /tmp/password +$ echo coleman > /tmp/certificate + +$ SECRET=/tmp/secret \ + CERTIFICATE_FILE=/tmp/certificate \ + go run main.go +{Secret:qwerty Password:dvorak Certificate:coleman} +``` + +## Options + +### Use field names as environment variables by default + +If you don't want to set the `env` tag on every field, you can use the +`UseFieldNameByDefault` option. + +It will use the field name as environment variable name. + +Here's an example: + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Username string // will use $USERNAME + Password string // will use $PASSWORD + UserFullName string // will use $USER_FULL_NAME +} + +func main() { + cfg := &Config{} + opts := env.Options{UseFieldNameByDefault: true} + + // Load env vars. + if err := env.ParseWithOptions(cfg, opts); err != nil { + log.Fatal(err) + } + + // Print the loaded data. + fmt.Printf("%+v\n", cfg) +} +``` + +### Environment + +By setting the `Options.Environment` map you can tell `Parse` to add those +`keys` and `values` as `env` vars before parsing is done. +These `envs` are stored in the map and never actually set by `os.Setenv`. +This option effectively makes `env` ignore the OS environment variables: only +the ones provided in the option are used. + +This can make your testing scenarios a bit more clean and easy to handle. + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Password string `env:"PASSWORD"` +} + +func main() { + cfg := &Config{} + opts := env.Options{Environment: map[string]string{ + "PASSWORD": "MY_PASSWORD", + }} + + // Load env vars. + if err := env.ParseWithOptions(cfg, opts); err != nil { + log.Fatal(err) + } + + // Print the loaded data. + fmt.Printf("%+v\n", cfg) +} +``` + +### Changing default tag name + +You can change what tag name to use for setting the env vars by setting the +`Options.TagName` variable. + +For example + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Password string `json:"PASSWORD"` +} + +func main() { + cfg := &Config{} + opts := env.Options{TagName: "json"} + + // Load env vars. + if err := env.ParseWithOptions(cfg, opts); err != nil { + log.Fatal(err) + } + + // Print the loaded data. + fmt.Printf("%+v\n", cfg) +} +``` + +### Prefixes + +You can prefix sub-structs env tags, as well as a whole `env.Parse` call. + +Here's an example flexing it a bit: + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Home string `env:"HOME"` +} + +type ComplexConfig struct { + Foo Config `envPrefix:"FOO_"` + Clean Config + Bar Config `envPrefix:"BAR_"` + Blah string `env:"BLAH"` +} + +func main() { + cfg := &ComplexConfig{} + opts := env.Options{ + Prefix: "T_", + Environment: map[string]string{ + "T_FOO_HOME": "/foo", + "T_BAR_HOME": "/bar", + "T_BLAH": "blahhh", + "T_HOME": "/clean", + }, + } + + // Load env vars. + if err := env.ParseWithOptions(cfg, opts); err != nil { + log.Fatal(err) + } + + // Print the loaded data. + fmt.Printf("%+v\n", cfg) +} +``` + +### On set hooks + +You might want to listen to value sets and, for example, log something or do +some other kind of logic. +You can do this by passing a `OnSet` option: + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Username string `env:"USERNAME" envDefault:"admin"` + Password string `env:"PASSWORD"` +} + +func main() { + cfg := &Config{} + opts := env.Options{ + OnSet: func(tag string, value interface{}, isDefault bool) { + fmt.Printf("Set %s to %v (default? %v)\n", tag, value, isDefault) + }, + } + + // Load env vars. + if err := env.ParseWithOptions(cfg, opts); err != nil { + log.Fatal(err) + } + + // Print the loaded data. + fmt.Printf("%+v\n", cfg) +} +``` + +## Making all fields to required + +You can make all fields that don't have a default value be required by setting +the `RequiredIfNoDef: true` in the `Options`. + +For example + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Username string `env:"USERNAME" envDefault:"admin"` + Password string `env:"PASSWORD"` +} + +func main() { + cfg := &Config{} + opts := env.Options{RequiredIfNoDef: true} + + // Load env vars. + if err := env.ParseWithOptions(cfg, opts); err != nil { + log.Fatal(err) + } + + // Print the loaded data. + fmt.Printf("%+v\n", cfg) +} +``` + +## Defaults from code + +You may define default value also in code, by initialising the config data +before it's filled by `env.Parse`. +Default values defined as struct tags will overwrite existing values during +Parse. + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Username string `env:"USERNAME" envDefault:"admin"` + Password string `env:"PASSWORD"` +} + +func main() { + cfg := Config{ + Username: "test", + Password: "123456", + } + + if err := env.Parse(&cfg); err != nil { + fmt.Println("failed:", err) + } + + fmt.Printf("%+v", cfg) // {Username:admin Password:123456} +} +``` + +## Error handling + +You can handle the errors the library throws like so: + +```go +package main + +import ( + "fmt" + "log" + + "github.com/caarlos0/env/v10" +) + +type Config struct { + Username string `env:"USERNAME" envDefault:"admin"` + Password string `env:"PASSWORD"` +} + +func main() { + var cfg Config + err := env.Parse(&cfg) + if e, ok := err.(*env.AggregateError); ok { + for _, er := range e.Errors { + switch v := er.(type) { + case env.ParseError: + // handle it + case env.NotStructPtrError: + // handle it + case env.NoParserError: + // handle it + case env.NoSupportedTagOptionError: + // handle it + default: + fmt.Printf("Unknown error type %v", v) + } + } + } + + fmt.Printf("%+v", cfg) // {Username:admin Password:123456} +} +``` + +> **Info** +> +> If you want to check if an specific error is in the chain, you can also use +> `errors.Is()`. + +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/caarlos0/env.svg)](https://starchart.cc/caarlos0/env) diff --git a/vendor/github.com/caarlos0/env/v10/env.go b/vendor/github.com/caarlos0/env/v10/env.go new file mode 100644 index 000000000..5c9d806c1 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/env.go @@ -0,0 +1,614 @@ +package env + +import ( + "encoding" + "fmt" + "net/url" + "os" + "reflect" + "strconv" + "strings" + "time" + "unicode" +) + +// nolint: gochecknoglobals +var ( + defaultBuiltInParsers = map[reflect.Kind]ParserFunc{ + reflect.Bool: func(v string) (interface{}, error) { + return strconv.ParseBool(v) + }, + reflect.String: func(v string) (interface{}, error) { + return v, nil + }, + reflect.Int: func(v string) (interface{}, error) { + i, err := strconv.ParseInt(v, 10, 32) + return int(i), err + }, + reflect.Int16: func(v string) (interface{}, error) { + i, err := strconv.ParseInt(v, 10, 16) + return int16(i), err + }, + reflect.Int32: func(v string) (interface{}, error) { + i, err := strconv.ParseInt(v, 10, 32) + return int32(i), err + }, + reflect.Int64: func(v string) (interface{}, error) { + return strconv.ParseInt(v, 10, 64) + }, + reflect.Int8: func(v string) (interface{}, error) { + i, err := strconv.ParseInt(v, 10, 8) + return int8(i), err + }, + reflect.Uint: func(v string) (interface{}, error) { + i, err := strconv.ParseUint(v, 10, 32) + return uint(i), err + }, + reflect.Uint16: func(v string) (interface{}, error) { + i, err := strconv.ParseUint(v, 10, 16) + return uint16(i), err + }, + reflect.Uint32: func(v string) (interface{}, error) { + i, err := strconv.ParseUint(v, 10, 32) + return uint32(i), err + }, + reflect.Uint64: func(v string) (interface{}, error) { + i, err := strconv.ParseUint(v, 10, 64) + return i, err + }, + reflect.Uint8: func(v string) (interface{}, error) { + i, err := strconv.ParseUint(v, 10, 8) + return uint8(i), err + }, + reflect.Float64: func(v string) (interface{}, error) { + return strconv.ParseFloat(v, 64) + }, + reflect.Float32: func(v string) (interface{}, error) { + f, err := strconv.ParseFloat(v, 32) + return float32(f), err + }, + } +) + +func defaultTypeParsers() map[reflect.Type]ParserFunc { + return map[reflect.Type]ParserFunc{ + reflect.TypeOf(url.URL{}): func(v string) (interface{}, error) { + u, err := url.Parse(v) + if err != nil { + return nil, newParseValueError("unable to parse URL", err) + } + return *u, nil + }, + reflect.TypeOf(time.Nanosecond): func(v string) (interface{}, error) { + s, err := time.ParseDuration(v) + if err != nil { + return nil, newParseValueError("unable to parse duration", err) + } + return s, err + }, + } +} + +// ParserFunc defines the signature of a function that can be used within `CustomParsers`. +type ParserFunc func(v string) (interface{}, error) + +// OnSetFn is a hook that can be run when a value is set. +type OnSetFn func(tag string, value interface{}, isDefault bool) + +// processFieldFn is a function which takes all information about a field and processes it. +type processFieldFn func(refField reflect.Value, refTypeField reflect.StructField, opts Options, fieldParams FieldParams) error + +// Options for the parser. +type Options struct { + // Environment keys and values that will be accessible for the service. + Environment map[string]string + + // TagName specifies another tagname to use rather than the default env. + TagName string + + // RequiredIfNoDef automatically sets all env as required if they do not + // declare 'envDefault'. + RequiredIfNoDef bool + + // OnSet allows to run a function when a value is set. + OnSet OnSetFn + + // Prefix define a prefix for each key. + Prefix string + + // UseFieldNameByDefault defines whether or not env should use the field + // name by default if the `env` key is missing. + UseFieldNameByDefault bool + + // Custom parse functions for different types. + FuncMap map[reflect.Type]ParserFunc + + // Used internally. maps the env variable key to its resolved string value. (for env var expansion) + rawEnvVars map[string]string +} + +func (opts *Options) getRawEnv(s string) string { + val := opts.rawEnvVars[s] + if val == "" { + return opts.Environment[s] + } + return val +} + +func defaultOptions() Options { + return Options{ + TagName: "env", + Environment: toMap(os.Environ()), + FuncMap: defaultTypeParsers(), + rawEnvVars: make(map[string]string), + } +} + +func customOptions(opt Options) Options { + defOpts := defaultOptions() + if opt.TagName == "" { + opt.TagName = defOpts.TagName + } + if opt.Environment == nil { + opt.Environment = defOpts.Environment + } + if opt.FuncMap == nil { + opt.FuncMap = map[reflect.Type]ParserFunc{} + } + if opt.rawEnvVars == nil { + opt.rawEnvVars = defOpts.rawEnvVars + } + for k, v := range defOpts.FuncMap { + if _, exists := opt.FuncMap[k]; !exists { + opt.FuncMap[k] = v + } + } + return opt +} + +func optionsWithEnvPrefix(field reflect.StructField, opts Options) Options { + return Options{ + Environment: opts.Environment, + TagName: opts.TagName, + RequiredIfNoDef: opts.RequiredIfNoDef, + OnSet: opts.OnSet, + Prefix: opts.Prefix + field.Tag.Get("envPrefix"), + UseFieldNameByDefault: opts.UseFieldNameByDefault, + FuncMap: opts.FuncMap, + rawEnvVars: opts.rawEnvVars, + } +} + +// Parse parses a struct containing `env` tags and loads its values from +// environment variables. +func Parse(v interface{}) error { + return parseInternal(v, setField, defaultOptions()) +} + +// ParseWithOptions parses a struct containing `env` tags and loads its values from +// environment variables. +func ParseWithOptions(v interface{}, opts Options) error { + return parseInternal(v, setField, customOptions(opts)) +} + +// GetFieldParams parses a struct containing `env` tags and returns information about +// tags it found. +func GetFieldParams(v interface{}) ([]FieldParams, error) { + return GetFieldParamsWithOptions(v, defaultOptions()) +} + +// GetFieldParamsWithOptions parses a struct containing `env` tags and returns information about +// tags it found. +func GetFieldParamsWithOptions(v interface{}, opts Options) ([]FieldParams, error) { + var result []FieldParams + err := parseInternal( + v, + func(_ reflect.Value, _ reflect.StructField, _ Options, fieldParams FieldParams) error { + if fieldParams.OwnKey != "" { + result = append(result, fieldParams) + } + return nil + }, + customOptions(opts), + ) + if err != nil { + return nil, err + } + + return result, nil +} + +func parseInternal(v interface{}, processField processFieldFn, opts Options) error { + ptrRef := reflect.ValueOf(v) + if ptrRef.Kind() != reflect.Ptr { + return newAggregateError(NotStructPtrError{}) + } + ref := ptrRef.Elem() + if ref.Kind() != reflect.Struct { + return newAggregateError(NotStructPtrError{}) + } + + return doParse(ref, processField, opts) +} + +func doParse(ref reflect.Value, processField processFieldFn, opts Options) error { + refType := ref.Type() + + var agrErr AggregateError + + for i := 0; i < refType.NumField(); i++ { + refField := ref.Field(i) + refTypeField := refType.Field(i) + + if err := doParseField(refField, refTypeField, processField, opts); err != nil { + if val, ok := err.(AggregateError); ok { + agrErr.Errors = append(agrErr.Errors, val.Errors...) + } else { + agrErr.Errors = append(agrErr.Errors, err) + } + } + } + + if len(agrErr.Errors) == 0 { + return nil + } + + return agrErr +} + +func doParseField(refField reflect.Value, refTypeField reflect.StructField, processField processFieldFn, opts Options) error { + if !refField.CanSet() { + return nil + } + if reflect.Ptr == refField.Kind() && !refField.IsNil() { + return parseInternal(refField.Interface(), processField, optionsWithEnvPrefix(refTypeField, opts)) + } + if reflect.Struct == refField.Kind() && refField.CanAddr() && refField.Type().Name() == "" { + return parseInternal(refField.Addr().Interface(), processField, optionsWithEnvPrefix(refTypeField, opts)) + } + + params, err := parseFieldParams(refTypeField, opts) + if err != nil { + return err + } + + if err := processField(refField, refTypeField, opts, params); err != nil { + return err + } + + if reflect.Struct == refField.Kind() { + return doParse(refField, processField, optionsWithEnvPrefix(refTypeField, opts)) + } + + return nil +} + +func setField(refField reflect.Value, refTypeField reflect.StructField, opts Options, fieldParams FieldParams) error { + value, err := get(fieldParams, opts) + if err != nil { + return err + } + + if value != "" { + return set(refField, refTypeField, value, opts.FuncMap) + } + + return nil +} + +const underscore rune = '_' + +func toEnvName(input string) string { + var output []rune + for i, c := range input { + if i > 0 && output[i-1] != underscore && c != underscore && unicode.ToUpper(c) == c { + output = append(output, underscore) + } + output = append(output, unicode.ToUpper(c)) + } + return string(output) +} + +// FieldParams contains information about parsed field tags. +type FieldParams struct { + OwnKey string + Key string + DefaultValue string + HasDefaultValue bool + Required bool + LoadFile bool + Unset bool + NotEmpty bool + Expand bool +} + +func parseFieldParams(field reflect.StructField, opts Options) (FieldParams, error) { + ownKey, tags := parseKeyForOption(field.Tag.Get(opts.TagName)) + if ownKey == "" && opts.UseFieldNameByDefault { + ownKey = toEnvName(field.Name) + } + + defaultValue, hasDefaultValue := field.Tag.Lookup("envDefault") + + result := FieldParams{ + OwnKey: ownKey, + Key: opts.Prefix + ownKey, + Required: opts.RequiredIfNoDef, + DefaultValue: defaultValue, + HasDefaultValue: hasDefaultValue, + } + + for _, tag := range tags { + switch tag { + case "": + continue + case "file": + result.LoadFile = true + case "required": + result.Required = true + case "unset": + result.Unset = true + case "notEmpty": + result.NotEmpty = true + case "expand": + result.Expand = true + default: + return FieldParams{}, newNoSupportedTagOptionError(tag) + } + } + + return result, nil +} + +func get(fieldParams FieldParams, opts Options) (val string, err error) { + var exists, isDefault bool + + val, exists, isDefault = getOr(fieldParams.Key, fieldParams.DefaultValue, fieldParams.HasDefaultValue, opts.Environment) + + if fieldParams.Expand { + val = os.Expand(val, opts.getRawEnv) + } + + opts.rawEnvVars[fieldParams.OwnKey] = val + + if fieldParams.Unset { + defer os.Unsetenv(fieldParams.Key) + } + + if fieldParams.Required && !exists && len(fieldParams.OwnKey) > 0 { + return "", newEnvVarIsNotSet(fieldParams.Key) + } + + if fieldParams.NotEmpty && val == "" { + return "", newEmptyEnvVarError(fieldParams.Key) + } + + if fieldParams.LoadFile && val != "" { + filename := val + val, err = getFromFile(filename) + if err != nil { + return "", newLoadFileContentError(filename, fieldParams.Key, err) + } + } + + if opts.OnSet != nil { + if fieldParams.OwnKey != "" { + opts.OnSet(fieldParams.Key, val, isDefault) + } + } + return val, err +} + +// split the env tag's key into the expected key and desired option, if any. +func parseKeyForOption(key string) (string, []string) { + opts := strings.Split(key, ",") + return opts[0], opts[1:] +} + +func getFromFile(filename string) (value string, err error) { + b, err := os.ReadFile(filename) + return string(b), err +} + +func getOr(key, defaultValue string, defExists bool, envs map[string]string) (val string, exists bool, isDefault bool) { + value, exists := envs[key] + switch { + case (!exists || key == "") && defExists: + return defaultValue, true, true + case exists && value == "" && defExists: + return defaultValue, true, true + case !exists: + return "", false, false + } + + return value, true, false +} + +func set(field reflect.Value, sf reflect.StructField, value string, funcMap map[reflect.Type]ParserFunc) error { + if tm := asTextUnmarshaler(field); tm != nil { + if err := tm.UnmarshalText([]byte(value)); err != nil { + return newParseError(sf, err) + } + return nil + } + + typee := sf.Type + fieldee := field + if typee.Kind() == reflect.Ptr { + typee = typee.Elem() + fieldee = field.Elem() + } + + parserFunc, ok := funcMap[typee] + if ok { + val, err := parserFunc(value) + if err != nil { + return newParseError(sf, err) + } + + fieldee.Set(reflect.ValueOf(val)) + return nil + } + + parserFunc, ok = defaultBuiltInParsers[typee.Kind()] + if ok { + val, err := parserFunc(value) + if err != nil { + return newParseError(sf, err) + } + + fieldee.Set(reflect.ValueOf(val).Convert(typee)) + return nil + } + + switch field.Kind() { + case reflect.Slice: + return handleSlice(field, value, sf, funcMap) + case reflect.Map: + return handleMap(field, value, sf, funcMap) + } + + return newNoParserError(sf) +} + +func handleSlice(field reflect.Value, value string, sf reflect.StructField, funcMap map[reflect.Type]ParserFunc) error { + separator := sf.Tag.Get("envSeparator") + if separator == "" { + separator = "," + } + parts := strings.Split(value, separator) + + typee := sf.Type.Elem() + if typee.Kind() == reflect.Ptr { + typee = typee.Elem() + } + + if _, ok := reflect.New(typee).Interface().(encoding.TextUnmarshaler); ok { + return parseTextUnmarshalers(field, parts, sf) + } + + parserFunc, ok := funcMap[typee] + if !ok { + parserFunc, ok = defaultBuiltInParsers[typee.Kind()] + if !ok { + return newNoParserError(sf) + } + } + + result := reflect.MakeSlice(sf.Type, 0, len(parts)) + for _, part := range parts { + r, err := parserFunc(part) + if err != nil { + return newParseError(sf, err) + } + v := reflect.ValueOf(r).Convert(typee) + if sf.Type.Elem().Kind() == reflect.Ptr { + v = reflect.New(typee) + v.Elem().Set(reflect.ValueOf(r).Convert(typee)) + } + result = reflect.Append(result, v) + } + field.Set(result) + return nil +} + +func handleMap(field reflect.Value, value string, sf reflect.StructField, funcMap map[reflect.Type]ParserFunc) error { + keyType := sf.Type.Key() + keyParserFunc, ok := funcMap[keyType] + if !ok { + keyParserFunc, ok = defaultBuiltInParsers[keyType.Kind()] + if !ok { + return newNoParserError(sf) + } + } + + elemType := sf.Type.Elem() + elemParserFunc, ok := funcMap[elemType] + if !ok { + elemParserFunc, ok = defaultBuiltInParsers[elemType.Kind()] + if !ok { + return newNoParserError(sf) + } + } + + separator := sf.Tag.Get("envSeparator") + if separator == "" { + separator = "," + } + + keyValSeparator := sf.Tag.Get("envKeyValSeparator") + if keyValSeparator == "" { + keyValSeparator = ":" + } + + result := reflect.MakeMap(sf.Type) + for _, part := range strings.Split(value, separator) { + pairs := strings.Split(part, keyValSeparator) + if len(pairs) != 2 { + return newParseError(sf, fmt.Errorf(`%q should be in "key%svalue" format`, part, keyValSeparator)) + } + + key, err := keyParserFunc(pairs[0]) + if err != nil { + return newParseError(sf, err) + } + + elem, err := elemParserFunc(pairs[1]) + if err != nil { + return newParseError(sf, err) + } + + result.SetMapIndex(reflect.ValueOf(key).Convert(keyType), reflect.ValueOf(elem).Convert(elemType)) + } + + field.Set(result) + return nil +} + +func asTextUnmarshaler(field reflect.Value) encoding.TextUnmarshaler { + if reflect.Ptr == field.Kind() { + if field.IsNil() { + field.Set(reflect.New(field.Type().Elem())) + } + } else if field.CanAddr() { + field = field.Addr() + } + + tm, ok := field.Interface().(encoding.TextUnmarshaler) + if !ok { + return nil + } + return tm +} + +func parseTextUnmarshalers(field reflect.Value, data []string, sf reflect.StructField) error { + s := len(data) + elemType := field.Type().Elem() + slice := reflect.MakeSlice(reflect.SliceOf(elemType), s, s) + for i, v := range data { + sv := slice.Index(i) + kind := sv.Kind() + if kind == reflect.Ptr { + sv = reflect.New(elemType.Elem()) + } else { + sv = sv.Addr() + } + tm := sv.Interface().(encoding.TextUnmarshaler) + if err := tm.UnmarshalText([]byte(v)); err != nil { + return newParseError(sf, err) + } + if kind == reflect.Ptr { + slice.Index(i).Set(sv) + } + } + + field.Set(slice) + + return nil +} + +// ToMap Converts list of env vars as provided by os.Environ() to map you +// can use as Options.Environment field +func ToMap(env []string) map[string]string { + return toMap(env) +} diff --git a/vendor/github.com/caarlos0/env/v10/env_tomap.go b/vendor/github.com/caarlos0/env/v10/env_tomap.go new file mode 100644 index 000000000..aece2ae9a --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/env_tomap.go @@ -0,0 +1,16 @@ +//go:build !windows + +package env + +import "strings" + +func toMap(env []string) map[string]string { + r := map[string]string{} + for _, e := range env { + p := strings.SplitN(e, "=", 2) + if len(p) == 2 { + r[p[0]] = p[1] + } + } + return r +} diff --git a/vendor/github.com/caarlos0/env/v10/env_tomap_windows.go b/vendor/github.com/caarlos0/env/v10/env_tomap_windows.go new file mode 100644 index 000000000..04ce66f57 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/env_tomap_windows.go @@ -0,0 +1,29 @@ +//go:build windows + +package env + +import "strings" + +func toMap(env []string) map[string]string { + r := map[string]string{} + for _, e := range env { + p := strings.SplitN(e, "=", 2) + + // On Windows, environment variables can start with '='. If so, Split at next character. + // See env_windows.go in the Go source: https://github.com/golang/go/blob/master/src/syscall/env_windows.go#L58 + prefixEqualSign := false + if len(e) > 0 && e[0] == '=' { + e = e[1:] + prefixEqualSign = true + } + p = strings.SplitN(e, "=", 2) + if prefixEqualSign { + p[0] = "=" + p[0] + } + + if len(p) == 2 { + r[p[0]] = p[1] + } + } + return r +} diff --git a/vendor/github.com/caarlos0/env/v10/error.go b/vendor/github.com/caarlos0/env/v10/error.go new file mode 100644 index 000000000..156ca3ec9 --- /dev/null +++ b/vendor/github.com/caarlos0/env/v10/error.go @@ -0,0 +1,164 @@ +package env + +import ( + "fmt" + "reflect" + "strings" +) + +// An aggregated error wrapper to combine gathered errors. This allows either to display all errors or convert them individually +// List of the available errors +// ParseError +// NotStructPtrError +// NoParserError +// NoSupportedTagOptionError +// EnvVarIsNotSetError +// EmptyEnvVarError +// LoadFileContentError +// ParseValueError +type AggregateError struct { + Errors []error +} + +func newAggregateError(initErr error) error { + return AggregateError{ + []error{ + initErr, + }, + } +} + +func (e AggregateError) Error() string { + var sb strings.Builder + + sb.WriteString("env:") + + for _, err := range e.Errors { + sb.WriteString(fmt.Sprintf(" %v;", err.Error())) + } + + return strings.TrimRight(sb.String(), ";") +} + +// Is conforms with errors.Is. +func (e AggregateError) Is(err error) bool { + for _, ie := range e.Errors { + if reflect.TypeOf(ie) == reflect.TypeOf(err) { + return true + } + } + return false +} + +// The error occurs when it's impossible to convert the value for given type. +type ParseError struct { + Name string + Type reflect.Type + Err error +} + +func newParseError(sf reflect.StructField, err error) error { + return ParseError{sf.Name, sf.Type, err} +} + +func (e ParseError) Error() string { + return fmt.Sprintf(`parse error on field "%s" of type "%s": %v`, e.Name, e.Type, e.Err) +} + +// The error occurs when pass something that is not a pointer to a Struct to Parse +type NotStructPtrError struct{} + +func (e NotStructPtrError) Error() string { + return "expected a pointer to a Struct" +} + +// This error occurs when there is no parser provided for given type +// Supported types and defaults: https://github.com/caarlos0/env#supported-types-and-defaults +// How to create a custom parser: https://github.com/caarlos0/env#custom-parser-funcs +type NoParserError struct { + Name string + Type reflect.Type +} + +func newNoParserError(sf reflect.StructField) error { + return NoParserError{sf.Name, sf.Type} +} + +func (e NoParserError) Error() string { + return fmt.Sprintf(`no parser found for field "%s" of type "%s"`, e.Name, e.Type) +} + +// This error occurs when the given tag is not supported +// In-built supported tags: "", "file", "required", "unset", "notEmpty", "expand", "envDefault", "envSeparator" +// How to create a custom tag: https://github.com/caarlos0/env#changing-default-tag-name +type NoSupportedTagOptionError struct { + Tag string +} + +func newNoSupportedTagOptionError(tag string) error { + return NoSupportedTagOptionError{tag} +} + +func (e NoSupportedTagOptionError) Error() string { + return fmt.Sprintf("tag option %q not supported", e.Tag) +} + +// This error occurs when the required variable is not set +// Read about required fields: https://github.com/caarlos0/env#required-fields +type EnvVarIsNotSetError struct { + Key string +} + +func newEnvVarIsNotSet(key string) error { + return EnvVarIsNotSetError{key} +} + +func (e EnvVarIsNotSetError) Error() string { + return fmt.Sprintf(`required environment variable %q is not set`, e.Key) +} + +// This error occurs when the variable which must be not empty is existing but has an empty value +// Read about not empty fields: https://github.com/caarlos0/env#not-empty-fields +type EmptyEnvVarError struct { + Key string +} + +func newEmptyEnvVarError(key string) error { + return EmptyEnvVarError{key} +} + +func (e EmptyEnvVarError) Error() string { + return fmt.Sprintf("environment variable %q should not be empty", e.Key) +} + +// This error occurs when it's impossible to load the value from the file +// Read about From file feature: https://github.com/caarlos0/env#from-file +type LoadFileContentError struct { + Filename string + Key string + Err error +} + +func newLoadFileContentError(filename, key string, err error) error { + return LoadFileContentError{filename, key, err} +} + +func (e LoadFileContentError) Error() string { + return fmt.Sprintf(`could not load content of file "%s" from variable %s: %v`, e.Filename, e.Key, e.Err) +} + +// This error occurs when it's impossible to convert value using given parser +// Supported types and defaults: https://github.com/caarlos0/env#supported-types-and-defaults +// How to create a custom parser: https://github.com/caarlos0/env#custom-parser-funcs +type ParseValueError struct { + Msg string + Err error +} + +func newParseValueError(message string, err error) error { + return ParseValueError{message, err} +} + +func (e ParseValueError) Error() string { + return fmt.Sprintf("%s: %v", e.Msg, e.Err) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c676ea9c2..b43b0ad71 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -76,9 +76,9 @@ github.com/bsm/redislock github.com/butuzov/ireturn/analyzer github.com/butuzov/ireturn/config github.com/butuzov/ireturn/types -# github.com/caarlos0/env v3.3.0+incompatible -## explicit -github.com/caarlos0/env +# github.com/caarlos0/env/v10 v10.0.0 +## explicit; go 1.17 +github.com/caarlos0/env/v10 # github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 ## explicit github.com/certifi/gocertifi From e8f5e66b62b37ba8a2bf4f21dc202774509cbc01 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:02:07 +0200 Subject: [PATCH 06/31] Update to github.com/caarlos0/env v10 --- backend/couchdb/db.go | 2 +- backend/k8sapi/client.go | 2 +- backend/objstore/objstore.go | 2 +- backend/postgres/postgres.go | 5 +++-- backend/queue/config.go | 2 +- backend/redis/redis.go | 2 +- grpc/server.go | 2 +- http/jsonapi/runtime/standard_params.go | 2 +- http/server.go | 2 +- http/transport/dump_round_tripper.go | 2 +- locale/cfg.go | 2 +- maintenance/health/servicehealthcheck/config.go | 2 +- maintenance/log/log.go | 2 +- pkg/routine/config.go | 2 +- test/livetest/init.go | 2 +- 15 files changed, 17 insertions(+), 16 deletions(-) diff --git a/backend/couchdb/db.go b/backend/couchdb/db.go index 345afbbbd..ca53d23b5 100644 --- a/backend/couchdb/db.go +++ b/backend/couchdb/db.go @@ -6,7 +6,7 @@ package couchdb import ( "context" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/go-kivik/couchdb/v3" kivik "github.com/go-kivik/kivik/v3" diff --git a/backend/k8sapi/client.go b/backend/k8sapi/client.go index 84da163df..32121e65a 100644 --- a/backend/k8sapi/client.go +++ b/backend/k8sapi/client.go @@ -15,7 +15,7 @@ import ( "os" "strings" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/pace/bricks/http/transport" "github.com/pace/bricks/maintenance/log" ) diff --git a/backend/objstore/objstore.go b/backend/objstore/objstore.go index 57993ab17..6eb692021 100644 --- a/backend/objstore/objstore.go +++ b/backend/objstore/objstore.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" diff --git a/backend/postgres/postgres.go b/backend/postgres/postgres.go index 6f3d97263..ef6bb4749 100644 --- a/backend/postgres/postgres.go +++ b/backend/postgres/postgres.go @@ -15,7 +15,7 @@ import ( "sync" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/go-pg/pg" "github.com/opentracing/opentracing-go" olog "github.com/opentracing/opentracing-go/log" @@ -224,7 +224,8 @@ func ConnectionPool(opts ...ConfigOption) *pg.DB { // // Fot a health check for this connection a PgHealthCheck needs to // be registered: -// servicehealthcheck.RegisterHealthCheck(...) +// +// servicehealthcheck.RegisterHealthCheck(...) func CustomConnectionPool(opts *pg.Options) *pg.DB { log.Logger().Info().Str("addr", opts.Addr). Str("user", opts.User). diff --git a/backend/queue/config.go b/backend/queue/config.go index a08ce7702..aa908fa4a 100644 --- a/backend/queue/config.go +++ b/backend/queue/config.go @@ -4,7 +4,7 @@ import ( "log" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" ) type config struct { diff --git a/backend/redis/redis.go b/backend/redis/redis.go index 01268097d..4ec7b9549 100755 --- a/backend/redis/redis.go +++ b/backend/redis/redis.go @@ -8,7 +8,7 @@ import ( "context" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/go-redis/redis/v7" "github.com/opentracing/opentracing-go" olog "github.com/opentracing/opentracing-go/log" diff --git a/grpc/server.go b/grpc/server.go index 0e67f6bae..34f30fab1 100644 --- a/grpc/server.go +++ b/grpc/server.go @@ -24,7 +24,7 @@ import ( "github.com/rs/zerolog" zlog "github.com/rs/zerolog/log" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" diff --git a/http/jsonapi/runtime/standard_params.go b/http/jsonapi/runtime/standard_params.go index 28435da37..d4c0c4baa 100644 --- a/http/jsonapi/runtime/standard_params.go +++ b/http/jsonapi/runtime/standard_params.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/go-pg/pg" "github.com/go-pg/pg/orm" diff --git a/http/server.go b/http/server.go index c04c4bfe2..ec3e11a5f 100644 --- a/http/server.go +++ b/http/server.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/pace/bricks/maintenance/log" ) diff --git a/http/transport/dump_round_tripper.go b/http/transport/dump_round_tripper.go index 2b4f645b5..227001741 100644 --- a/http/transport/dump_round_tripper.go +++ b/http/transport/dump_round_tripper.go @@ -11,7 +11,7 @@ import ( "net/url" "strings" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/pace/bricks/maintenance/log" "github.com/pace/bricks/pkg/redact" diff --git a/locale/cfg.go b/locale/cfg.go index a1e270704..b025e761c 100644 --- a/locale/cfg.go +++ b/locale/cfg.go @@ -6,7 +6,7 @@ package locale import ( "log" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" ) type config struct { diff --git a/maintenance/health/servicehealthcheck/config.go b/maintenance/health/servicehealthcheck/config.go index 76ed2d735..65e9a44ff 100644 --- a/maintenance/health/servicehealthcheck/config.go +++ b/maintenance/health/servicehealthcheck/config.go @@ -3,7 +3,7 @@ package servicehealthcheck import ( "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/pace/bricks/maintenance/log" ) diff --git a/maintenance/log/log.go b/maintenance/log/log.go index eeafe192f..b36529826 100644 --- a/maintenance/log/log.go +++ b/maintenance/log/log.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/pace/bricks/maintenance/log/hlog" "github.com/rs/zerolog" diff --git a/pkg/routine/config.go b/pkg/routine/config.go index 7d87ca937..e059a8791 100644 --- a/pkg/routine/config.go +++ b/pkg/routine/config.go @@ -6,7 +6,7 @@ package routine import ( "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" ) type config struct { diff --git a/test/livetest/init.go b/test/livetest/init.go index 672ed586d..282cece1f 100644 --- a/test/livetest/init.go +++ b/test/livetest/init.go @@ -7,7 +7,7 @@ import ( "log" "time" - "github.com/caarlos0/env" + "github.com/caarlos0/env/v10" "github.com/prometheus/client_golang/prometheus" ) From 8d94f06fdb9342fa40fc52d75d5b939f5f3830ad Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:04:26 +0200 Subject: [PATCH 07/31] gomod: Update github.com/certifi/gocertifi --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/certifi/gocertifi/LICENSE | 376 ++- vendor/github.com/certifi/gocertifi/README.md | 33 +- .../github.com/certifi/gocertifi/certifi.go | 2587 +++++------------ vendor/github.com/certifi/gocertifi/tasks.py | 20 - vendor/modules.txt | 4 +- 7 files changed, 1074 insertions(+), 1952 deletions(-) delete mode 100644 vendor/github.com/certifi/gocertifi/tasks.py diff --git a/go.mod b/go.mod index 16fa86761..9d427bd71 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/bsm/redislock v0.5.0 github.com/caarlos0/env/v10 v10.0.0 - github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 + github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d github.com/dave/jennifer v1.0.2 github.com/getkin/kin-openapi v0.0.0-20180813063848-e1956e8013e5 github.com/go-kivik/couchdb/v3 v3.2.6 diff --git a/go.sum b/go.sum index f4533371c..4b4450949 100644 --- a/go.sum +++ b/go.sum @@ -106,8 +106,8 @@ github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacM github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= +github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= diff --git a/vendor/github.com/certifi/gocertifi/LICENSE b/vendor/github.com/certifi/gocertifi/LICENSE index cfd5dcbbb..14e2f777f 100644 --- a/vendor/github.com/certifi/gocertifi/LICENSE +++ b/vendor/github.com/certifi/gocertifi/LICENSE @@ -1,3 +1,373 @@ -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain -one at http://mozilla.org/MPL/2.0/. +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/certifi/gocertifi/README.md b/vendor/github.com/certifi/gocertifi/README.md index 1c01b1102..9c860301d 100644 --- a/vendor/github.com/certifi/gocertifi/README.md +++ b/vendor/github.com/certifi/gocertifi/README.md @@ -9,28 +9,42 @@ This is the same CA bundle that ships with the Golang specific port of [certifi](https://github.com/kennethreitz/certifi). The CA bundle is derived from Mozilla's canonical set. -## Usage +## Usage You can use the `gocertifi` package as follows: ```go import "github.com/certifi/gocertifi" -cert_pool, err := gocertifi.CACerts() +certPool, err := gocertifi.CACerts() ``` You can use the returned `*x509.CertPool` as part of an HTTP transport, for example: ```go import ( - "net/http" - "crypto/tls" + "net/http" + "crypto/tls" ) // Setup an HTTP client with a custom transport transport := &http.Transport{ - TLSClientConfig: &tls.Config{RootCAs: cert_pool}, + Proxy: ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, } +// or, starting with go1.13 simply use: +// transport := http.DefaultTransport.(*http.Transport).Clone() + +transport.TLSClientConfig = &tls.Config{RootCAs: certPool} client := &http.Client{Transport: transport} // Make an HTTP request using our custom transport @@ -45,16 +59,11 @@ Import as follows: import "github.com/certifi/gocertifi" ``` -### Errors - -```go -var ErrParseFailed = errors.New("gocertifi: error when parsing certificates") -``` - ### Functions ```go func CACerts() (*x509.CertPool, error) ``` CACerts builds an X.509 certificate pool containing the Mozilla CA Certificate -bundle. Returns nil on error along with an appropriate error code. +bundle. This can't actually error and always returns successfully with `nil` +as the error. This will be replaced in `v2` to only return the `CertPool`. diff --git a/vendor/github.com/certifi/gocertifi/certifi.go b/vendor/github.com/certifi/gocertifi/certifi.go index 75bf74f68..70be286dc 100644 --- a/vendor/github.com/certifi/gocertifi/certifi.go +++ b/vendor/github.com/certifi/gocertifi/certifi.go @@ -1,19 +1,18 @@ +// Code generated by go generate; DO NOT EDIT. +// 2021-05-07 14:14:36.874796853 -0700 PDT m=+0.476299993 +// https://mkcert.org/generate/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + package gocertifi -import ( - "crypto/x509" - "errors" -) +//go:generate go run gen.go "https://mkcert.org/generate/" -const pemcerts string = ` +import "crypto/x509" -# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA -# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA -# Label: "GlobalSign Root CA" -# Serial: 4835703278459707669005204 -# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a -# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c -# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +const pemcerts string = ` -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv @@ -35,14 +34,6 @@ AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Label: "GlobalSign Root CA - R2" -# Serial: 4835703278459682885658125 -# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 -# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe -# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp @@ -65,46 +56,6 @@ ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- - -# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only -# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only -# Label: "Verisign Class 3 Public Primary Certification Authority - G3" -# Serial: 206684696279472310254277870180966723415 -# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09 -# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6 -# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44 ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b -N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t -KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu -kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm -CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ -Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu -imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te -2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe -DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC -/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p -F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt -TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- - -# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited -# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited -# Label: "Entrust.net Premium 2048 Secure Server CA" -# Serial: 946069240 -# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 -# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 -# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp @@ -130,14 +81,6 @@ u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er fF6adulZkMV8gzURZVE= -----END CERTIFICATE----- - -# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Label: "Baltimore CyberTrust Root" -# Serial: 33554617 -# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 -# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 -# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD @@ -159,47 +102,6 @@ Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- - -# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network -# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network -# Label: "AddTrust External Root" -# Serial: 1 -# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f -# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68 -# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2 ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs -IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 -MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h -bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v -dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt -H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 -uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX -mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX -a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN -E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 -WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD -VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 -Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx -IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN -AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH -YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC -Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX -c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a -mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. -# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. -# Label: "Entrust Root Certification Authority" -# Serial: 1164660820 -# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 -# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 -# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 @@ -227,150 +129,6 @@ AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- - -# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc. -# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. -# Label: "GeoTrust Global CA" -# Serial: 144470 -# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 -# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 -# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ------END CERTIFICATE----- - -# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. -# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. -# Label: "GeoTrust Universal CA" -# Serial: 1 -# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 -# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 -# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy -c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 -IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV -VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 -cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT -QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh -F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v -c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w -mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd -VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX -teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ -f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe -Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ -nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB -/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY -MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG -9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX -IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn -ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z -uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN -Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja -QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW -koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 -ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt -DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm -bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- - -# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. -# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. -# Label: "GeoTrust Universal CA 2" -# Serial: 1 -# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 -# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 -# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy -c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD -VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 -c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 -WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG -FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq -XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL -se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb -KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd -IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 -y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt -hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc -QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 -Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV -HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ -KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ -L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr -Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo -ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY -T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz -GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m -1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV -OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH -6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX -QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- - -# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association -# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association -# Label: "Visa eCommerce Root" -# Serial: 25952180776285836048024890241505565794 -# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02 -# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62 -# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22 ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr -MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl -cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv -bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw -CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h -dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l -cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h -2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E -lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV -ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq -299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t -vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL -dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF -AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR -zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 -LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd -7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw -++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt -398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- - -# Issuer: CN=AAA Certificate Services O=Comodo CA Limited -# Subject: CN=AAA Certificate Services O=Comodo CA Limited -# Label: "Comodo AAA Services root" -# Serial: 1 -# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 -# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 -# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow @@ -396,14 +154,6 @@ G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority -# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority -# Label: "QuoVadis Root CA" -# Serial: 985026699 -# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24 -# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9 -# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73 -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 @@ -438,14 +188,6 @@ mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK SnQ2+Q== -----END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2" -# Serial: 1289 -# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b -# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 -# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv @@ -479,14 +221,6 @@ ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y 4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza 8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3" -# Serial: 1478 -# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf -# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 -# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv @@ -525,14 +259,6 @@ Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK 4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- - -# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 -# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 -# Label: "Security Communication Root CA" -# Serial: 0 -# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a -# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 -# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t @@ -553,14 +279,6 @@ Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== -----END CERTIFICATE----- - -# Issuer: CN=Sonera Class2 CA O=Sonera -# Subject: CN=Sonera Class2 CA O=Sonera -# Label: "Sonera Class 2 Root CA" -# Serial: 29 -# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb -# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27 -# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27 -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx @@ -580,14 +298,6 @@ FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M -----END CERTIFICATE----- - -# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com -# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com -# Label: "XRamp Global CA Root" -# Serial: 107108908803651509692980124233745014957 -# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 -# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 -# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk @@ -613,14 +323,6 @@ IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ O+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- - -# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority -# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority -# Label: "Go Daddy Class 2 CA" -# Serial: 0 -# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 -# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 -# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE @@ -645,14 +347,6 @@ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf ReYNnyicsbkqWletNw+vHX/bvZ8= -----END CERTIFICATE----- - -# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority -# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority -# Label: "Starfield Class 2 CA" -# Serial: 0 -# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 -# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a -# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp @@ -677,54 +371,6 @@ xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- - -# Issuer: O=Government Root Certification Authority -# Subject: O=Government Root Certification Authority -# Label: "Taiwan GRCA" -# Serial: 42023070807708724159991140556527066870 -# MD5 Fingerprint: 37:85:44:53:32:45:1f:20:f0:f3:95:e1:25:c4:43:4e -# SHA1 Fingerprint: f4:8b:11:bf:de:ab:be:94:54:20:71:e6:41:de:6b:be:88:2b:40:b9 -# SHA256 Fingerprint: 76:00:29:5e:ef:e8:5b:9e:1f:d6:24:db:76:06:2a:aa:ae:59:81:8a:54:d2:77:4c:d4:c0:b2:c0:11:31:e1:b3 ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ -MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow -PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR -IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q -gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy -yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts -F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 -jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx -ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC -VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK -YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH -EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN -Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud -DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE -MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK -UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ -TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf -qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK -ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE -JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 -hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 -EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm -nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX -udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz -ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe -LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl -pYYsfPQS ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root CA" -# Serial: 17154717934120587862167794914071425081 -# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 -# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 -# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -747,14 +393,6 @@ NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root CA" -# Serial: 10944719598952040374951832963794454346 -# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e -# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 -# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -777,14 +415,6 @@ PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- - -# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert High Assurance EV Root CA" -# Serial: 3553400076410547919724730734378100087 -# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a -# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 -# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -808,44 +438,6 @@ Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- - -# Issuer: CN=Class 2 Primary CA O=Certplus -# Subject: CN=Class 2 Primary CA O=Certplus -# Label: "Certplus Class 2 Primary CA" -# Serial: 177770208045934040241468760488327595043 -# MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b -# SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb -# SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb ------BEGIN CERTIFICATE----- -MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw -PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz -cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 -MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz -IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ -ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR -VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL -kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd -EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas -H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 -HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud -DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 -QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu -Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ -AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 -yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR -FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA -ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB -kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 -l7+ijrRU ------END CERTIFICATE----- - -# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. -# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. -# Label: "DST Root CA X3" -# Serial: 91299735575339953335919266965803778155 -# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 -# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 -# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT @@ -866,14 +458,6 @@ R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- - -# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Label: "SwissSign Gold CA - G2" -# Serial: 13492815561806991280 -# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 -# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 -# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln @@ -907,14 +491,6 @@ Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- - -# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG -# Label: "SwissSign Silver CA - G2" -# Serial: 5700383053117599563 -# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 -# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb -# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu @@ -948,112 +524,6 @@ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- - -# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. -# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. -# Label: "GeoTrust Primary Certification Authority" -# Serial: 32798226551256963324313806436981982369 -# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf -# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 -# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY -MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo -R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx -MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 -AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA -ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 -7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W -kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI -mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ -KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 -6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl -4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K -oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj -UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU -AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- - -# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only -# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only -# Label: "thawte Primary Root CA" -# Serial: 69529181992039203566298953787712940909 -# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 -# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 -# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB -qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV -BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw -NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j -LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG -A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs -W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta -3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk -6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 -Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J -NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP -r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU -DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz -YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 -/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ -LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 -jVaMaA== ------END CERTIFICATE----- - -# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only -# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only -# Label: "VeriSign Class 3 Public Primary Certification Authority - G5" -# Serial: 33037644167568058970164719475676101450 -# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c -# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 -# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 -nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex -t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz -SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG -BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ -rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ -NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E -BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH -BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv -MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE -p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y -5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK -WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ -4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N -hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- - -# Issuer: CN=SecureTrust CA O=SecureTrust Corporation -# Subject: CN=SecureTrust CA O=SecureTrust Corporation -# Label: "SecureTrust CA" -# Serial: 17199774589125277788362757014266862032 -# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 -# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 -# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x @@ -1076,14 +546,6 @@ D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- - -# Issuer: CN=Secure Global CA O=SecureTrust Corporation -# Subject: CN=Secure Global CA O=SecureTrust Corporation -# Label: "Secure Global CA" -# Serial: 9751836167731051554232119481456978597 -# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de -# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b -# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x @@ -1106,14 +568,6 @@ I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- - -# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO Certification Authority O=COMODO CA Limited -# Label: "COMODO Certification Authority" -# Serial: 104350513648249232941998508985834464573 -# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 -# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b -# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G @@ -1139,14 +593,6 @@ zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB ZQ== -----END CERTIFICATE----- - -# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Label: "Network Solutions Certificate Authority" -# Serial: 116697915152937497490437556386812487904 -# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e -# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce -# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu @@ -1170,14 +616,6 @@ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- - -# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Label: "COMODO ECC Certification Authority" -# Serial: 41578283867086692638256921589707938090 -# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 -# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 -# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE @@ -1194,46 +632,6 @@ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GA CA" -# Serial: 86718877871133159090080555911823548314 -# MD5 Fingerprint: bc:6c:51:33:a7:e9:d3:66:63:54:15:72:1b:21:92:93 -# SHA1 Fingerprint: 59:22:a1:e1:5a:ea:16:35:21:f8:98:39:6a:46:46:b0:44:1b:0f:a9 -# SHA256 Fingerprint: 41:c9:23:86:6a:b4:ca:d6:b7:ad:57:80:81:58:2e:02:07:97:a6:cb:df:4f:ff:78:ce:83:96:b3:89:37:d7:f5 ------BEGIN CERTIFICATE----- -MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB -ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly -aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl -ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w -NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G -A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD -VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX -SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR -VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 -w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF -mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg -4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 -4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw -EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx -SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 -ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 -vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa -hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi -Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ -/L7fCg0= ------END CERTIFICATE----- - -# Issuer: CN=Certigna O=Dhimyotis -# Subject: CN=Certigna O=Dhimyotis -# Label: "Certigna" -# Serial: 18364802974209362175 -# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff -# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 -# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X @@ -1256,44 +654,6 @@ HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- - -# Issuer: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center -# Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center -# Label: "Deutsche Telekom Root CA 2" -# Serial: 38 -# MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08 -# SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf -# SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3 ------BEGIN CERTIFICATE----- -MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc -MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj -IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB -IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE -RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl -U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 -IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU -ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC -QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr -rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S -NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc -QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH -txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP -BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC -AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp -tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa -IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl -6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ -xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU -Cm26OWMohpLzGITY+9HPBVZkVw== ------END CERTIFICATE----- - -# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc -# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc -# Label: "Cybertrust Global Root" -# Serial: 4835703278459682877484360 -# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 -# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 -# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh @@ -1316,14 +676,6 @@ omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW WL1WMRJOEcgh4LMRkWXbtKaIOM5V -----END CERTIFICATE----- - -# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Label: "ePKI Root Certification Authority" -# Serial: 28956088682735189655030529057352760477 -# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 -# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 -# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 @@ -1357,14 +709,6 @@ Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D hNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- - -# Issuer: O=certSIGN OU=certSIGN ROOT CA -# Subject: O=certSIGN OU=certSIGN ROOT CA -# Label: "certSIGN ROOT CA" -# Serial: 35210227249154 -# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 -# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b -# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD @@ -1385,193 +729,6 @@ Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN 9u6wWk5JRFRYX0KD -----END CERTIFICATE----- - -# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only -# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only -# Label: "GeoTrust Primary Certification Authority - G3" -# Serial: 28809105769928564313984085209975885599 -# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 -# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd -# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 ------BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB -mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT -MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ -BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg -MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 -BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz -+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm -hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn -5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W -JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL -DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC -huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB -AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB -zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN -kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD -AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH -SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G -spki4cErx5z481+oghLrGREt ------END CERTIFICATE----- - -# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only -# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only -# Label: "thawte Primary Root CA - G2" -# Serial: 71758320672825410020661621085256472406 -# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f -# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 -# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp -IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi -BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw -MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig -YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v -dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ -BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 -papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K -DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 -KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox -XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- - -# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only -# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only -# Label: "thawte Primary Root CA - G3" -# Serial: 127614157056681299805556476275995414779 -# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 -# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 -# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB -rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV -BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa -Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl -LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u -MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl -ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm -gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 -YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf -b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 -9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S -zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk -OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA -2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW -oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu -t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c -KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM -m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu -MdRAGmI0Nj81Aa6sY6A= ------END CERTIFICATE----- - -# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only -# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only -# Label: "GeoTrust Primary Certification Authority - G2" -# Serial: 80682863203381065782177908751794619243 -# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a -# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 -# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 ------BEGIN CERTIFICATE----- -MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL -MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj -KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 -MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV -BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw -NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV -BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH -MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL -So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal -tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG -CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT -qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz -rD6ogRLQy7rQkgu2npaqBA+K ------END CERTIFICATE----- - -# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only -# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only -# Label: "VeriSign Universal Root Certification Authority" -# Serial: 85209574734084581917763752644031726877 -# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 -# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 -# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c ------BEGIN CERTIFICATE----- -MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB -vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W -ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 -IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y -IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh -bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF -9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH -H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H -LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN -/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT -rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw -WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs -exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud -DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 -sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ -seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz -4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ -BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR -lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 -7M2CYfE45k+XmCpajQ== ------END CERTIFICATE----- - -# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only -# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only -# Label: "VeriSign Class 3 Public Primary Certification Authority - G4" -# Serial: 63143484348153506665311985501458640051 -# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 -# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a -# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 ------BEGIN CERTIFICATE----- -MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp -U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg -SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln -biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm -GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve -fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ -aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj -aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW -kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC -4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga -FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== ------END CERTIFICATE----- - -# Issuer: CN=NetLock Arany (Class Gold) Főtanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services) -# Subject: CN=NetLock Arany (Class Gold) Főtanúsítvány O=NetLock Kft. OU=Tanúsítványkiadók (Certification Services) -# Label: "NetLock Arany (Class Gold) Főtanúsítvány" -# Serial: 80544274841616 -# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 -# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 -# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 @@ -1596,55 +753,6 @@ bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- - -# Issuer: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden -# Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden -# Label: "Staat der Nederlanden Root CA - G2" -# Serial: 10000012 -# MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a -# SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16 -# SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f ------BEGIN CERTIFICATE----- -MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX -DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl -ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv -b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 -qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp -uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU -Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE -pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp -5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M -UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN -GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy -5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv -6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK -eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 -B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ -BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov -L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG -SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS -CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen -5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 -IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK -gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL -+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL -vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm -bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk -N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC -Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z -ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post -# Label: "Hongkong Post Root CA 1" -# Serial: 1000 -# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca -# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 -# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg @@ -1665,14 +773,6 @@ EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi AmvZWg== -----END CERTIFICATE----- - -# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. -# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. -# Label: "SecureSign RootCA11" -# Serial: 1 -# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 -# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 -# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG @@ -1694,14 +794,6 @@ QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN QSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- - -# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Label: "Microsec e-Szigno Root CA 2009" -# Serial: 14014712776195784473 -# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 -# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e -# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 @@ -1726,14 +818,6 @@ tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c 2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW -----END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp @@ -1755,14 +839,6 @@ mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH WD9f -----END CERTIFICATE----- - -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 6047274297262753887 -# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 -# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa -# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h @@ -1798,14 +874,6 @@ StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- - -# Issuer: CN=Izenpe.com O=IZENPE S.A. -# Subject: CN=Izenpe.com O=IZENPE S.A. -# Label: "Izenpe.com" -# Serial: 917563065490389241595536686991402621 -# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 -# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 -# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 @@ -1840,113 +908,6 @@ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- - -# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. -# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. -# Label: "Chambers of Commerce Root - 2008" -# Serial: 11806822484801597146 -# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7 -# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c -# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0 ------BEGIN CERTIFICATE----- -MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD -VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 -IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 -MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz -IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz -MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj -dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw -EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp -MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G -CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 -28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq -VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q -DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR -5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL -ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a -Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl -UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s -+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 -Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj -ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx -hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV -HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 -+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN -YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t -L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy -ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt -IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV -HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w -DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW -PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF -5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 -glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH -FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 -pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD -xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG -tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq -jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De -fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg -OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ -d0jQ ------END CERTIFICATE----- - -# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. -# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. -# Label: "Global Chambersign Root - 2008" -# Serial: 14541511773111788494 -# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3 -# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c -# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD -VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 -IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 -MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx -MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy -cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG -A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl -BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI -hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed -KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 -G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 -zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 -ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG -HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 -Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V -yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e -beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r -6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog -zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW -BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr -ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp -ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk -cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt -YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC -CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow -KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI -hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ -UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz -X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x -fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz -a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd -Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd -SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O -AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso -M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge -v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- - -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT @@ -1970,14 +931,6 @@ gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 4uJEvlz36hz1 -----END CERTIFICATE----- - -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT @@ -2001,14 +954,6 @@ sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- - -# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Services Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 -# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f -# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT @@ -2033,14 +978,6 @@ iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn 0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN sSi6 -----END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Commercial O=AffirmTrust -# Subject: CN=AffirmTrust Commercial O=AffirmTrust -# Label: "AffirmTrust Commercial" -# Serial: 8608355977964138876 -# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 -# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 -# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz @@ -2061,14 +998,6 @@ Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Networking O=AffirmTrust -# Subject: CN=AffirmTrust Networking O=AffirmTrust -# Label: "AffirmTrust Networking" -# Serial: 8957382827206547757 -# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f -# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f -# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz @@ -2089,14 +1018,6 @@ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Premium O=AffirmTrust -# Subject: CN=AffirmTrust Premium O=AffirmTrust -# Label: "AffirmTrust Premium" -# Serial: 7893706540734352110 -# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 -# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 -# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz @@ -2128,14 +1049,6 @@ GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e KeC2uAloGRwYQw== -----END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust -# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust -# Label: "AffirmTrust Premium ECC" -# Serial: 8401224907861490260 -# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d -# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb -# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ @@ -2149,14 +1062,6 @@ A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== -----END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D @@ -2179,14 +1084,6 @@ J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- - -# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Label: "TWCA Root Certification Authority" -# Serial: 1 -# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 -# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 -# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU @@ -2208,14 +1105,6 @@ lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- - -# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Label: "Security Communication RootCA2" -# Serial: 0 -# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 -# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 -# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe @@ -2237,14 +1126,37 @@ t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy 1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2011" -# Serial: 0 -# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 -# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d -# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 @@ -2270,14 +1182,6 @@ dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI l7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- - -# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Label: "Actalis Authentication Root CA" -# Serial: 6271844772424770508 -# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 -# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac -# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w @@ -2311,14 +1215,6 @@ ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- - -# Issuer: O=Trustis Limited OU=Trustis FPS Root CA -# Subject: O=Trustis Limited OU=Trustis FPS Root CA -# Label: "Trustis FPS Root CA" -# Serial: 36053640375399034304724988975563710553 -# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d -# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04 -# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL @@ -2340,14 +1236,6 @@ f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN ZetX2fNXlrtIzYE= -----END CERTIFICATE----- - -# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 2 Root CA" -# Serial: 2 -# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 -# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 -# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg @@ -2379,14 +1267,6 @@ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= -----END CERTIFICATE----- - -# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 3 Root CA" -# Serial: 2 -# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec -# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 -# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg @@ -2418,14 +1298,6 @@ kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq 4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= -----END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 3" -# Serial: 1 -# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef -# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 -# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd @@ -2449,46 +1321,6 @@ WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p TpPDpFQUWw== -----END CERTIFICATE----- - -# Issuer: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus -# Subject: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus -# Label: "EE Certification Centre Root CA" -# Serial: 112324828676200291871926431888494945866 -# MD5 Fingerprint: 43:5e:88:d4:7d:1a:4a:7e:fd:84:2e:52:eb:01:d4:6f -# SHA1 Fingerprint: c9:a8:b9:e7:55:80:5e:58:e3:53:77:a7:25:eb:af:c3:7b:27:cc:d7 -# SHA256 Fingerprint: 3e:84:ba:43:42:90:85:16:e7:75:73:c0:99:2f:09:79:ca:08:4e:46:85:68:1f:f1:95:cc:ba:8a:22:9b:8a:76 ------BEGIN CERTIFICATE----- -MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 -MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 -czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG -CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy -MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl -ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS -b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy -euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO -bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw -WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d -MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE -1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ -zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB -BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF -BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV -v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG -E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u -uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW -iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v -GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 2009" -# Serial: 623603 -# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f -# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 -# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD @@ -2514,14 +1346,6 @@ zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y Johw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 EV 2009" -# Serial: 623604 -# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 -# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 -# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD @@ -2547,14 +1371,6 @@ CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 -----END CERTIFICATE----- - -# Issuer: CN=CA Disig Root R2 O=Disig a.s. -# Subject: CN=CA Disig Root R2 O=Disig a.s. -# Label: "CA Disig Root R2" -# Serial: 10572350602393338211 -# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 -# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 -# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu @@ -2586,14 +1402,6 @@ G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- - -# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Label: "ACCVRAIZ1" -# Serial: 6828503384748696800 -# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 -# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 -# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw @@ -2638,14 +1446,6 @@ h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 -----END CERTIFICATE----- - -# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA Global Root CA" -# Serial: 3262 -# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 -# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 -# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT @@ -2677,14 +1477,6 @@ wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy KwbQBM0= -----END CERTIFICATE----- - -# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Label: "TeliaSonera Root CA v1" -# Serial: 199041966741090107964904287217786801558 -# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c -# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 -# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv @@ -2715,14 +1507,6 @@ t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- - -# Issuer: CN=E-Tugra Certification Authority O=E-Tuğra EBG Bilişim Teknolojileri ve Hizmetleri A.Ş. OU=E-Tugra Sertifikasyon Merkezi -# Subject: CN=E-Tugra Certification Authority O=E-Tuğra EBG Bilişim Teknolojileri ve Hizmetleri A.Ş. OU=E-Tugra Sertifikasyon Merkezi -# Label: "E-Tugra Certification Authority" -# Serial: 7667447206703254355 -# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 -# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 -# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC @@ -2759,14 +1543,6 @@ AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 2" -# Serial: 1 -# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a -# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 -# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd @@ -2790,14 +1566,6 @@ g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP BSeOE6Fuwg== -----END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot 2011 O=Atos -# Subject: CN=Atos TrustedRoot 2011 O=Atos -# Label: "Atos TrustedRoot 2011" -# Serial: 6643877497813316402 -# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 -# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 -# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG @@ -2819,14 +1587,6 @@ maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 1 G3" -# Serial: 687049649626669250736271037606554624078720034195 -# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab -# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 -# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc @@ -2858,14 +1618,6 @@ ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD -----END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2 G3" -# Serial: 390156079458959257446133169266079962026824725800 -# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 -# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 -# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc @@ -2897,14 +1649,6 @@ KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M -----END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3 G3" -# Serial: 268090761170461462463995952157327242137089239581 -# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 -# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d -# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc @@ -2936,14 +1680,6 @@ DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G2" -# Serial: 15385348160840213938643033620894905419 -# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d -# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f -# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -2966,14 +1702,6 @@ B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G3" -# Serial: 15459312981008553731928384953135426796 -# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb -# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 -# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu @@ -2989,14 +1717,6 @@ AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 6pZjamVFkpUBtA== -----END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -3019,14 +1739,6 @@ Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu @@ -3042,14 +1754,6 @@ AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 sycX -----END CERTIFICATE----- - -# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Trusted Root G4" -# Serial: 7451500558977370777930084869016614236 -# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 -# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 -# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 @@ -3082,14 +1786,6 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ -----END CERTIFICATE----- - -# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Label: "COMODO RSA Certification Authority" -# Serial: 101909084537582093308941363524873193117 -# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 -# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 -# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G @@ -3124,14 +1820,6 @@ QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB NVOFBkpdn627G190 -----END CERTIFICATE----- - -# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Label: "USERTrust RSA Certification Authority" -# Serial: 2645093764781058787591871645665788717 -# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 -# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e -# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl @@ -3166,14 +1854,6 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG jjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- - -# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Label: "USERTrust ECC Certification Authority" -# Serial: 123013823720199481456569720443997572134 -# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 -# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 -# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a -----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl @@ -3190,14 +1870,6 @@ VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Label: "GlobalSign ECC Root CA - R4" -# Serial: 14367148294922964480859022125800977897474 -# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e -# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb -# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH @@ -3211,14 +1883,6 @@ uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs ewv4n4Q= -----END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Label: "GlobalSign ECC Root CA - R5" -# Serial: 32785792099990507226680698011560947931244 -# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 -# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa -# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH @@ -3233,54 +1897,6 @@ KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg 515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO xwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- - -# Issuer: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden -# Subject: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden -# Label: "Staat der Nederlanden Root CA - G3" -# Serial: 10003001 -# MD5 Fingerprint: 0b:46:67:07:db:10:2f:19:8c:35:50:60:d1:0b:f4:37 -# SHA1 Fingerprint: d8:eb:6b:41:51:92:59:e0:f3:e7:85:00:c0:3d:b6:88:97:c9:ee:fc -# SHA256 Fingerprint: 3c:4f:b0:b9:5a:b8:b3:00:32:f4:32:b8:6f:53:5f:e1:72:c1:85:d0:fd:39:86:58:37:cf:36:18:7f:a6:f4:28 ------BEGIN CERTIFICATE----- -MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX -DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl -ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv -b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP -cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW -IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX -xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy -KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR -9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az -5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 -6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 -Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP -bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt -BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt -XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd -INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD -U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp -LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 -Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp -gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh -/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw -0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A -fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq -4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR -1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ -QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM -94B7IWcnMFk= ------END CERTIFICATE----- - -# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Label: "Staat der Nederlanden EV Root CA" -# Serial: 10000013 -# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba -# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb -# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh @@ -3313,14 +1929,6 @@ eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc 7uzXLg== -----END CERTIFICATE----- - -# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Label: "IdenTrust Commercial Root CA 1" -# Serial: 13298821034946342390520003877796839426 -# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 -# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 -# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu @@ -3352,14 +1960,6 @@ l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A 7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H -----END CERTIFICATE----- - -# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Label: "IdenTrust Public Sector Root CA 1" -# Serial: 13298821034946342390521976156843933698 -# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba -# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd -# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu @@ -3391,14 +1991,6 @@ tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv 8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c -----END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - G2" -# Serial: 1246989352 -# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 -# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 -# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 @@ -3424,14 +2016,6 @@ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== -----END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - EC1" -# Serial: 51543124481930649114116133369 -# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc -# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 -# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 @@ -3450,14 +2034,6 @@ BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- - -# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority -# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority -# Label: "CFCA EV ROOT" -# Serial: 407555286 -# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 -# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 -# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y @@ -3490,87 +2066,6 @@ Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ 5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- - -# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. -# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş. -# Label: "TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5" -# Serial: 156233699172481 -# MD5 Fingerprint: da:70:8e:f0:22:df:93:26:f6:5f:9f:d3:15:06:52:4e -# SHA1 Fingerprint: c4:18:f6:4d:46:d1:df:00:3d:27:30:13:72:43:a9:12:11:c6:75:fb -# SHA256 Fingerprint: 49:35:1b:90:34:44:c1:85:cc:dc:5c:69:3d:24:d8:55:5c:b2:08:d6:a8:14:13:07:69:9f:4a:f0:63:19:9d:78 ------BEGIN CERTIFICATE----- -MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE -BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn -aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg -QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg -SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0 -MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD -VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 -dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom -/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR -Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3 -4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z -5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0 -hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID -AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX -SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l -VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq -URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf -peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF -Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW -+qtB4Uu2NQvAmxU= ------END CERTIFICATE----- - -# Issuer: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 -# Subject: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 -# Label: "Certinomis - Root CA" -# Serial: 1 -# MD5 Fingerprint: 14:0a:fd:8d:a8:28:b5:38:69:db:56:7e:61:22:03:3f -# SHA1 Fingerprint: 9d:70:bb:01:a5:a4:a0:18:11:2e:f7:1c:01:b9:32:c5:34:e7:88:a8 -# SHA256 Fingerprint: 2a:99:f5:bc:11:74:b7:3c:bb:1d:62:08:84:e0:1c:34:e5:1c:cb:39:78:da:12:5f:0e:33:26:88:83:bf:41:58 ------BEGIN CERTIFICATE----- -MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET -MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb -BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz -MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx -FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g -Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 -fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl -LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV -WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF -TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb -5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc -CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri -wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ -wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG -m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 -F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng -WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 -2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF -AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ -0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw -F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS -g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj -qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN -h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ -ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V -btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj -Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ -8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW -gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GB CA" -# Serial: 157768595616588414422159278966750757568 -# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d -# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed -# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg @@ -3593,14 +2088,6 @@ ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= -----END CERTIFICATE----- - -# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Label: "SZAFIR ROOT CA2" -# Serial: 357043034767186914217277344587386743377558296292 -# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 -# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de -# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe -----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 @@ -3622,14 +2109,6 @@ oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== -----END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA 2" -# Serial: 44979900017204383099463764357512596969 -# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 -# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 -# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 -----BEGIN CERTIFICATE----- MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu @@ -3664,14 +2143,6 @@ XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P 5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi DrW5viSP -----END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce -# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 -# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 -----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k @@ -3707,14 +2178,6 @@ pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 vm9qp/UsQu0yrbYhnr68 -----END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef -# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 -# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 -----BEGIN CERTIFICATE----- MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl @@ -3732,177 +2195,6 @@ C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR -----END CERTIFICATE----- - -# Issuer: CN=Certplus Root CA G1 O=Certplus -# Subject: CN=Certplus Root CA G1 O=Certplus -# Label: "Certplus Root CA G1" -# Serial: 1491911565779898356709731176965615564637713 -# MD5 Fingerprint: 7f:09:9c:f7:d9:b9:5c:69:69:56:d5:37:3e:14:0d:42 -# SHA1 Fingerprint: 22:fd:d0:b7:fd:a2:4e:0d:ac:49:2c:a0:ac:a6:7b:6a:1f:e3:f7:66 -# SHA256 Fingerprint: 15:2a:40:2b:fc:df:2c:d5:48:05:4d:22:75:b3:9c:7f:ca:3e:c0:97:80:78:b0:f0:ea:76:e5:61:a6:c7:43:3e ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA -MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy -dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa -MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy -dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a -iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt -6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP -0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f -6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE -EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN -1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc -h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT -mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV -4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO -WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud -DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd -Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq -hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh -66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7 -/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS -S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j -2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R -Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr -RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy -6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV -V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5 -g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl -++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= ------END CERTIFICATE----- - -# Issuer: CN=Certplus Root CA G2 O=Certplus -# Subject: CN=Certplus Root CA G2 O=Certplus -# Label: "Certplus Root CA G2" -# Serial: 1492087096131536844209563509228951875861589 -# MD5 Fingerprint: a7:ee:c4:78:2d:1b:ee:2d:b9:29:ce:d6:a7:96:32:31 -# SHA1 Fingerprint: 4f:65:8e:1f:e9:06:d8:28:02:e9:54:47:41:c9:54:25:5d:69:cc:1a -# SHA256 Fingerprint: 6c:c0:50:41:e6:44:5e:74:69:6c:4c:fb:c9:f8:0f:54:3b:7e:ab:bb:44:b4:ce:6f:78:7c:6a:99:71:c4:2f:17 ------BEGIN CERTIFICATE----- -MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x -CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs -dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x -CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs -dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat -93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x -Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P -AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj -FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG -SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch -p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal -U5ORGpOucGpnutee5WEaXw== ------END CERTIFICATE----- - -# Issuer: CN=OpenTrust Root CA G1 O=OpenTrust -# Subject: CN=OpenTrust Root CA G1 O=OpenTrust -# Label: "OpenTrust Root CA G1" -# Serial: 1492036577811947013770400127034825178844775 -# MD5 Fingerprint: 76:00:cc:81:29:cd:55:5e:88:6a:7a:2e:f7:4d:39:da -# SHA1 Fingerprint: 79:91:e8:34:f7:e2:ee:dd:08:95:01:52:e9:55:2d:14:e9:58:d5:7e -# SHA256 Fingerprint: 56:c7:71:28:d9:8c:18:d9:1b:4c:fd:ff:bc:25:ee:91:03:d4:75:8e:a2:ab:ad:82:6a:90:f3:45:7d:46:0e:b4 ------BEGIN CERTIFICATE----- -MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA -MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w -ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw -MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU -T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b -wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX -/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0 -77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP -uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx -p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx -Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2 -TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W -G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw -vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY -EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1 -2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw -DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E -PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf -gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS -FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0 -V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P -XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I -i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t -TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91 -09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky -Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ -AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj -1oxx ------END CERTIFICATE----- - -# Issuer: CN=OpenTrust Root CA G2 O=OpenTrust -# Subject: CN=OpenTrust Root CA G2 O=OpenTrust -# Label: "OpenTrust Root CA G2" -# Serial: 1492012448042702096986875987676935573415441 -# MD5 Fingerprint: 57:24:b6:59:24:6b:ae:c8:fe:1c:0c:20:f2:c0:4e:eb -# SHA1 Fingerprint: 79:5f:88:60:c5:ab:7c:3d:92:e6:cb:f4:8d:e1:45:cd:11:ef:60:0b -# SHA256 Fingerprint: 27:99:58:29:fe:6a:75:15:c1:bf:e8:48:f9:c4:76:1d:b1:6c:22:59:29:25:7b:f4:0d:08:94:f2:9e:a8:ba:f2 ------BEGIN CERTIFICATE----- -MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA -MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w -ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw -MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU -T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh -/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e -CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6 -1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE -FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS -gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X -G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy -YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH -vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4 -t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/ -gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3 -5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w -DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz -Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0 -nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT -RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT -wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2 -t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa -TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2 -o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU -3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA -iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f -WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM -S1IK ------END CERTIFICATE----- - -# Issuer: CN=OpenTrust Root CA G3 O=OpenTrust -# Subject: CN=OpenTrust Root CA G3 O=OpenTrust -# Label: "OpenTrust Root CA G3" -# Serial: 1492104908271485653071219941864171170455615 -# MD5 Fingerprint: 21:37:b4:17:16:92:7b:67:46:70:a9:96:d7:a8:13:24 -# SHA1 Fingerprint: 6e:26:64:f3:56:bf:34:55:bf:d1:93:3f:7c:01:de:d8:13:da:8a:a6 -# SHA256 Fingerprint: b7:c3:62:31:70:6e:81:07:8c:36:7c:b8:96:19:8f:1e:32:08:dd:92:69:49:dd:8f:57:09:a4:10:f7:5b:62:92 ------BEGIN CERTIFICATE----- -MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx -CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U -cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow -QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl -blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm -3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d -oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G -A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5 -DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK -BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q -j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx -4nxp5V2a+EEfOzmTk51V6s2N8fvB ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh @@ -3934,14 +2226,6 @@ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- - -# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Label: "AC RAIZ FNMT-RCM" -# Serial: 485876308206448804701554682760554759 -# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d -# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 -# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ @@ -3974,14 +2258,6 @@ fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= -----END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 1 O=Amazon -# Subject: CN=Amazon Root CA 1 O=Amazon -# Label: "Amazon Root CA 1" -# Serial: 143266978916655856878034712317230054538369994 -# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 -# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 -# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e -----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 @@ -4002,14 +2278,6 @@ o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy rqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 2 O=Amazon -# Subject: CN=Amazon Root CA 2 O=Amazon -# Label: "Amazon Root CA 2" -# Serial: 143266982885963551818349160658925006970653239 -# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 -# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a -# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 @@ -4041,14 +2309,6 @@ n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE 9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT 4PsJYGw= -----END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 3 O=Amazon -# Subject: CN=Amazon Root CA 3 O=Amazon -# Label: "Amazon Root CA 3" -# Serial: 143266986699090766294700635381230934788665930 -# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 -# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e -# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 -----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g @@ -4061,14 +2321,6 @@ ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM YyRIHN8wfdVoOw== -----END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 4 O=Amazon -# Subject: CN=Amazon Root CA 4 O=Amazon -# Label: "Amazon Root CA 4" -# Serial: 143266989758080763974105200630763877849284878 -# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd -# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be -# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 -----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g @@ -4082,55 +2334,6 @@ MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW 1KyLa2tJElMzrdfkviT8tQp21KW8EA== -----END CERTIFICATE----- - -# Issuer: CN=LuxTrust Global Root 2 O=LuxTrust S.A. -# Subject: CN=LuxTrust Global Root 2 O=LuxTrust S.A. -# Label: "LuxTrust Global Root 2" -# Serial: 59914338225734147123941058376788110305822489521 -# MD5 Fingerprint: b2:e1:09:00:61:af:f7:f1:91:6f:c4:ad:8d:5e:3b:7c -# SHA1 Fingerprint: 1e:0e:56:19:0a:d1:8b:25:98:b2:04:44:ff:66:8a:04:17:99:5f:3f -# SHA256 Fingerprint: 54:45:5f:71:29:c2:0b:14:47:c4:18:f9:97:16:8f:24:c5:8f:c5:02:3b:f5:da:5b:e2:eb:6e:1d:d8:90:2e:d5 ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- - -# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" -# Serial: 1 -# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 -# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca -# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 -----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp @@ -4157,14 +2360,6 @@ lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c 8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= -----END CERTIFICATE----- - -# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Label: "GDCA TrustAUTH R5 ROOT" -# Serial: 9009899650740120186 -# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 -# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 -# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 -----BEGIN CERTIFICATE----- MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ @@ -4197,14 +2392,6 @@ XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== -----END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-1" -# Serial: 15752444095811006489 -# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 -# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a -# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk @@ -4230,14 +2417,6 @@ yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN zl/HHk484IkzlQsPpTLWPFp5LBk= -----END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-2" -# Serial: 2711694510199101698 -# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 -# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 -# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 -----BEGIN CERTIFICATE----- MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw @@ -4274,14 +2453,6 @@ As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp 5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu 1uwJ -----END CERTIFICATE----- - -# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor ECA-1" -# Serial: 9548242946988625984 -# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c -# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd -# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk @@ -4307,14 +2478,6 @@ soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi tJ/X5g== -----END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Label: "SSL.com Root Certification Authority RSA" -# Serial: 8875640296558310041 -# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 -# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb -# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 -----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK @@ -4349,14 +2512,6 @@ nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY Ic2wBlX7Jz9TkHCpBB5XJ7k= -----END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com Root Certification Authority ECC" -# Serial: 8495723813297216424 -# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e -# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a -# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 -----BEGIN CERTIFICATE----- MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T @@ -4373,14 +2528,6 @@ VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl -----END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority RSA R2" -# Serial: 6248227494352943350 -# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 -# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a -# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c -----BEGIN CERTIFICATE----- MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE @@ -4415,14 +2562,6 @@ w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== -----END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority ECC" -# Serial: 3182246526754555285 -# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 -# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d -# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 -----BEGIN CERTIFICATE----- MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T @@ -4439,18 +2578,642 @@ MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== -----END CERTIFICATE----- -` +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- -var ErrParseFailed = errors.New("gocertifi: error when parsing certificates") +` -// CACerts builds an X.509 certificate pool containing the Mozilla CA -// Certificate bundle. Returns nil on error along with an appropriate error -// code. +// CACerts builds an X.509 certificate pool containing the +// certificate bundle from https://mkcert.org/generate/ fetch on 2021-05-07 14:14:36.874796853 -0700 PDT m=+0.476299993. +// Will never actually return an error. func CACerts() (*x509.CertPool, error) { pool := x509.NewCertPool() - ok := pool.AppendCertsFromPEM([]byte(pemcerts)) - if !ok { - return nil, ErrParseFailed - } + pool.AppendCertsFromPEM([]byte(pemcerts)) return pool, nil } diff --git a/vendor/github.com/certifi/gocertifi/tasks.py b/vendor/github.com/certifi/gocertifi/tasks.py deleted file mode 100644 index 7616f3a6a..000000000 --- a/vendor/github.com/certifi/gocertifi/tasks.py +++ /dev/null @@ -1,20 +0,0 @@ -from invoke import task -import requests - -@task -def update(ctx): - r = requests.get('https://mkcert.org/generate/') - r.raise_for_status() - certs = r.content - - with open('certifi.go', 'rb') as f: - file = f.read() - - file = file.split('`\n') - assert len(file) == 3 - file[1] = certs - - ctx.run("rm certifi.go") - - with open('certifi.go', 'wb') as f: - f.write('`\n'.join(file)) diff --git a/vendor/modules.txt b/vendor/modules.txt index b43b0ad71..28b4463bf 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -79,8 +79,8 @@ github.com/butuzov/ireturn/types # github.com/caarlos0/env/v10 v10.0.0 ## explicit; go 1.17 github.com/caarlos0/env/v10 -# github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 -## explicit +# github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d +## explicit; go 1.12 github.com/certifi/gocertifi # github.com/cespare/xxhash/v2 v2.2.0 ## explicit; go 1.11 From cc801a9f195792c06465a1d0afb2e68ace12850e Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:05:21 +0200 Subject: [PATCH 08/31] gomod: Update github.com/dave/jennifer --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/dave/jennifer/jen/file.go | 48 +++--- vendor/github.com/dave/jennifer/jen/group.go | 32 ++-- vendor/github.com/dave/jennifer/jen/hints.go | 138 ++++++++++-------- vendor/github.com/dave/jennifer/jen/jen.go | 10 +- .../github.com/dave/jennifer/jen/reserved.go | 20 +++ .../github.com/dave/jennifer/jen/statement.go | 25 ++-- vendor/github.com/dave/jennifer/jen/tokens.go | 4 +- vendor/modules.txt | 4 +- 10 files changed, 181 insertions(+), 106 deletions(-) create mode 100644 vendor/github.com/dave/jennifer/jen/reserved.go diff --git a/go.mod b/go.mod index 9d427bd71..e4dec0f79 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/bsm/redislock v0.5.0 github.com/caarlos0/env/v10 v10.0.0 github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d - github.com/dave/jennifer v1.0.2 + github.com/dave/jennifer v1.4.1 github.com/getkin/kin-openapi v0.0.0-20180813063848-e1956e8013e5 github.com/go-kivik/couchdb/v3 v3.2.6 github.com/go-kivik/kivik/v3 v3.2.3 diff --git a/go.sum b/go.sum index 4b4450949..1e19d86d9 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDU github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daixiang0/gci v0.9.1 h1:jBrwBmBZTDsGsXiaCTLIe9diotp1X4X64zodFrh7l+c= github.com/daixiang0/gci v0.9.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= -github.com/dave/jennifer v1.0.2 h1:ixSwWgh8HCIJN9GlVNvdbKHrD/qfh5Mvd4ZCaFAJbr8= -github.com/dave/jennifer v1.0.2/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/dave/jennifer v1.4.1 h1:XyqG6cn5RQsTj3qlWQTKlRGAyrTcsk1kUmWdZBzRjDw= +github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA= 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= diff --git a/vendor/github.com/dave/jennifer/jen/file.go b/vendor/github.com/dave/jennifer/jen/file.go index 9d86b930f..c19f51651 100644 --- a/vendor/github.com/dave/jennifer/jen/file.go +++ b/vendor/github.com/dave/jennifer/jen/file.go @@ -5,6 +5,8 @@ import ( "fmt" "regexp" "strings" + "unicode" + "unicode/utf8" ) // NewFile Creates a new file, with the specified package name. @@ -60,6 +62,8 @@ type File struct { // If you're worried about generated package aliases conflicting with local variable names, you // can set a prefix here. Package foo becomes {prefix}_foo. PackagePrefix string + // CanonicalPath adds a canonical import path annotation to the package clause. + CanonicalPath string } // importdef is used to differentiate packages where we know the package name from packages where the @@ -112,7 +116,8 @@ func (f *File) ImportNames(names map[string]string) { } } -// ImportAlias provides the alias for a package path that should be used in the import block. +// ImportAlias provides the alias for a package path that should be used in the import block. A +// period can be used to force a dot-import. func (f *File) ImportAlias(path, alias string) { f.hints[path] = importdef{name: alias, alias: true} } @@ -121,27 +126,13 @@ func (f *File) isLocal(path string) bool { return f.path == path } -var reserved = []string{ - /* keywords */ - "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", - /* predeclared */ - "bool", "byte", "complex64", "complex128", "error", "float32", "float64", "int", "int8", "int16", "int32", "int64", "rune", "string", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "true", "false", "iota", "nil", "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", "panic", "print", "println", "real", "recover", - /* common variables */ - "err", -} - -func isReservedWord(alias string) bool { - for _, name := range reserved { - if alias == name { - return true - } - } - return false -} - func (f *File) isValidAlias(alias string) bool { + // multiple dot-imports are ok + if alias == "." { + return true + } // the import alias is invalid if it's a reserved word - if isReservedWord(alias) { + if IsReservedWord(alias) { return false } // the import alias is invalid if it's already been registered @@ -153,6 +144,13 @@ func (f *File) isValidAlias(alias string) bool { return true } +func (f *File) isDotImport(path string) bool { + if id, ok := f.hints[path]; ok { + return id.name == "." && id.alias + } + return false +} + func (f *File) register(path string) string { if f.isLocal(path) { // notest @@ -244,5 +242,15 @@ func guessAlias(path string) string { importsRegex := regexp.MustCompile(`[^a-z0-9]`) alias = importsRegex.ReplaceAllString(alias, "") + // can't have a first digit, per Go identifier rules, so just skip them + for firstRune, runeLen := utf8.DecodeRuneInString(alias); unicode.IsDigit(firstRune); firstRune, runeLen = utf8.DecodeRuneInString(alias) { + alias = alias[runeLen:] + } + + // If path part was all digits, we may be left with an empty string. In this case use "pkg" as the alias. + if alias == "" { + alias = "pkg" + } + return alias } diff --git a/vendor/github.com/dave/jennifer/jen/group.go b/vendor/github.com/dave/jennifer/jen/group.go index fdb501012..0b85c9017 100644 --- a/vendor/github.com/dave/jennifer/jen/group.go +++ b/vendor/github.com/dave/jennifer/jen/group.go @@ -43,7 +43,6 @@ func (g *Group) render(f *File, w io.Writer, s *Statement) error { if isGrp && grp.name == "case" || isTkn && tkn.content == "default" { g.open = "" g.close = "" - g.separator = "\n" } } if g.open != "" { @@ -79,6 +78,12 @@ func (g *Group) render(f *File, w io.Writer, s *Statement) error { func (g *Group) renderItems(f *File, w io.Writer) (isNull bool, err error) { first := true for _, code := range g.items { + if pt, ok := code.(token); ok && pt.typ == packageToken { + // Special case for package tokens in Qual groups - for dot-imports, the package token + // will be null, so will not render and will not be registered in the imports block. + // This ensures all packageTokens that are rendered are registered. + f.register(pt.content.(string)) + } if code == nil || code.isNull(f) { // Null() token produces no output but also // no separator. Empty() token products no @@ -112,9 +117,22 @@ func (g *Group) renderItems(f *File, w io.Writer) (isNull bool, err error) { // Render renders the Group to the provided writer. func (g *Group) Render(writer io.Writer) error { - f := NewFile("") + return g.RenderWithFile(writer, NewFile("")) +} + +// GoString renders the Group for testing. Any error will cause a panic. +func (g *Group) GoString() string { + buf := bytes.Buffer{} + if err := g.Render(&buf); err != nil { + panic(err) + } + return buf.String() +} + +// RenderWithFile renders the Group to the provided writer, using imports from the provided file. +func (g *Group) RenderWithFile(writer io.Writer, file *File) error { buf := &bytes.Buffer{} - if err := g.render(f, buf, nil); err != nil { + if err := g.render(file, buf, nil); err != nil { return err } b, err := format.Source(buf.Bytes()) @@ -127,11 +145,3 @@ func (g *Group) Render(writer io.Writer) error { return nil } -// GoString renders the Group for testing. Any error will cause a panic. -func (g *Group) GoString() string { - buf := bytes.Buffer{} - if err := g.Render(&buf); err != nil { - panic(err) - } - return buf.String() -} diff --git a/vendor/github.com/dave/jennifer/jen/hints.go b/vendor/github.com/dave/jennifer/jen/hints.go index 821d15f63..7bc307a65 100644 --- a/vendor/github.com/dave/jennifer/jen/hints.go +++ b/vendor/github.com/dave/jennifer/jen/hints.go @@ -25,6 +25,7 @@ var standardLibraryHints = map[string]string{ "cmd/compile/internal/syntax": "syntax", "cmd/compile/internal/test": "test", "cmd/compile/internal/types": "types", + "cmd/compile/internal/wasm": "wasm", "cmd/compile/internal/x86": "x86", "cmd/go/internal/base": "base", "cmd/go/internal/bug": "bug", @@ -32,6 +33,7 @@ var standardLibraryHints = map[string]string{ "cmd/go/internal/cfg": "cfg", "cmd/go/internal/clean": "clean", "cmd/go/internal/cmdflag": "cmdflag", + "cmd/go/internal/dirhash": "dirhash", "cmd/go/internal/doc": "doc", "cmd/go/internal/envcmd": "envcmd", "cmd/go/internal/fix": "fix", @@ -39,15 +41,32 @@ var standardLibraryHints = map[string]string{ "cmd/go/internal/generate": "generate", "cmd/go/internal/get": "get", "cmd/go/internal/help": "help", + "cmd/go/internal/imports": "imports", "cmd/go/internal/list": "list", "cmd/go/internal/load": "load", + "cmd/go/internal/modcmd": "modcmd", + "cmd/go/internal/modconv": "modconv", + "cmd/go/internal/modfetch": "modfetch", + "cmd/go/internal/modfetch/codehost": "codehost", + "cmd/go/internal/modfile": "modfile", + "cmd/go/internal/modget": "modget", + "cmd/go/internal/modinfo": "modinfo", + "cmd/go/internal/modload": "modload", + "cmd/go/internal/module": "module", + "cmd/go/internal/mvs": "mvs", + "cmd/go/internal/par": "par", "cmd/go/internal/run": "run", + "cmd/go/internal/search": "search", + "cmd/go/internal/semver": "semver", "cmd/go/internal/str": "str", "cmd/go/internal/test": "test", "cmd/go/internal/tool": "tool", + "cmd/go/internal/txtar": "txtar", "cmd/go/internal/version": "version", "cmd/go/internal/vet": "vet", "cmd/go/internal/web": "web", + "cmd/go/internal/web2": "web2", + "cmd/go/internal/webtest": "webtest", "cmd/go/internal/work": "work", "cmd/internal/bio": "bio", "cmd/internal/browser": "browser", @@ -62,6 +81,7 @@ var standardLibraryHints = map[string]string{ "cmd/internal/obj/mips": "mips", "cmd/internal/obj/ppc64": "ppc64", "cmd/internal/obj/s390x": "s390x", + "cmd/internal/obj/wasm": "wasm", "cmd/internal/obj/x86": "x86", "cmd/internal/objabi": "objabi", "cmd/internal/objfile": "objfile", @@ -81,6 +101,7 @@ var standardLibraryHints = map[string]string{ "cmd/link/internal/ppc64": "ppc64", "cmd/link/internal/s390x": "s390x", "cmd/link/internal/sym": "sym", + "cmd/link/internal/wasm": "wasm", "cmd/link/internal/x86": "x86", "cmd/vet/internal/cfg": "cfg", "cmd/vet/internal/whitelist": "whitelist", @@ -101,7 +122,8 @@ var standardLibraryHints = map[string]string{ "crypto/ecdsa": "ecdsa", "crypto/elliptic": "elliptic", "crypto/hmac": "hmac", - "crypto/internal/cipherhw": "cipherhw", + "crypto/internal/randutil": "randutil", + "crypto/internal/subtle": "subtle", "crypto/md5": "md5", "crypto/rand": "rand", "crypto/rc4": "rc4", @@ -167,11 +189,13 @@ var standardLibraryHints = map[string]string{ "image/jpeg": "jpeg", "image/png": "png", "index/suffixarray": "suffixarray", + "internal/bytealg": "bytealg", "internal/cpu": "cpu", "internal/nettrace": "nettrace", "internal/poll": "poll", "internal/race": "race", "internal/singleflight": "singleflight", + "internal/syscall/unix": "unix", "internal/syscall/windows": "windows", "internal/syscall/windows/registry": "registry", "internal/syscall/windows/sysdll": "sysdll", @@ -190,60 +214,60 @@ var standardLibraryHints = map[string]string{ "mime": "mime", "mime/multipart": "multipart", "mime/quotedprintable": "quotedprintable", - "net": "net", - "net/http": "http", - "net/http/cgi": "cgi", - "net/http/cookiejar": "cookiejar", - "net/http/fcgi": "fcgi", - "net/http/httptest": "httptest", - "net/http/httptrace": "httptrace", - "net/http/httputil": "httputil", - "net/http/internal": "internal", - "net/http/pprof": "pprof", - "net/internal/socktest": "socktest", - "net/mail": "mail", - "net/rpc": "rpc", - "net/rpc/jsonrpc": "jsonrpc", - "net/smtp": "smtp", - "net/textproto": "textproto", - "net/url": "url", - "os": "os", - "os/exec": "exec", - "os/signal": "signal", - "os/signal/internal/pty": "pty", - "os/user": "user", - "path": "path", - "path/filepath": "filepath", - "plugin": "plugin", - "reflect": "reflect", - "regexp": "regexp", - "regexp/syntax": "syntax", - "runtime": "runtime", - "runtime/cgo": "cgo", - "runtime/debug": "debug", - "runtime/internal/atomic": "atomic", - "runtime/internal/sys": "sys", - "runtime/pprof": "pprof", - "runtime/pprof/internal/profile": "profile", - "runtime/race": "race", - "runtime/trace": "trace", - "sort": "sort", - "strconv": "strconv", - "strings": "strings", - "sync": "sync", - "sync/atomic": "atomic", - "syscall": "syscall", - "testing": "testing", - "testing/internal/testdeps": "testdeps", - "testing/iotest": "iotest", - "testing/quick": "quick", - "text/scanner": "scanner", - "text/tabwriter": "tabwriter", - "text/template": "template", - "text/template/parse": "parse", - "time": "time", - "unicode": "unicode", - "unicode/utf16": "utf16", - "unicode/utf8": "utf8", - "unsafe": "unsafe", + "net": "net", + "net/http": "http", + "net/http/cgi": "cgi", + "net/http/cookiejar": "cookiejar", + "net/http/fcgi": "fcgi", + "net/http/httptest": "httptest", + "net/http/httptrace": "httptrace", + "net/http/httputil": "httputil", + "net/http/internal": "internal", + "net/http/pprof": "pprof", + "net/internal/socktest": "socktest", + "net/mail": "mail", + "net/rpc": "rpc", + "net/rpc/jsonrpc": "jsonrpc", + "net/smtp": "smtp", + "net/textproto": "textproto", + "net/url": "url", + "os": "os", + "os/exec": "exec", + "os/signal": "signal", + "os/signal/internal/pty": "pty", + "os/user": "user", + "path": "path", + "path/filepath": "filepath", + "plugin": "plugin", + "reflect": "reflect", + "regexp": "regexp", + "regexp/syntax": "syntax", + "runtime": "runtime", + "runtime/cgo": "cgo", + "runtime/debug": "debug", + "runtime/internal/atomic": "atomic", + "runtime/internal/sys": "sys", + "runtime/pprof": "pprof", + "runtime/pprof/internal/profile": "profile", + "runtime/race": "race", + "runtime/trace": "trace", + "sort": "sort", + "strconv": "strconv", + "strings": "strings", + "sync": "sync", + "sync/atomic": "atomic", + "syscall": "syscall", + "testing": "testing", + "testing/internal/testdeps": "testdeps", + "testing/iotest": "iotest", + "testing/quick": "quick", + "text/scanner": "scanner", + "text/tabwriter": "tabwriter", + "text/template": "template", + "text/template/parse": "parse", + "time": "time", + "unicode": "unicode", + "unicode/utf16": "utf16", + "unicode/utf8": "utf8", + "unsafe": "unsafe", } diff --git a/vendor/github.com/dave/jennifer/jen/jen.go b/vendor/github.com/dave/jennifer/jen/jen.go index 367d77ebe..4cf480a14 100644 --- a/vendor/github.com/dave/jennifer/jen/jen.go +++ b/vendor/github.com/dave/jennifer/jen/jen.go @@ -60,7 +60,15 @@ func (f *File) Render(w io.Writer) error { return err } } - if _, err := fmt.Fprintf(source, "package %s\n\n", f.name); err != nil { + if _, err := fmt.Fprintf(source, "package %s", f.name); err != nil { + return err + } + if f.CanonicalPath != "" { + if _, err := fmt.Fprintf(source, " // import %q", f.CanonicalPath); err != nil { + return err + } + } + if _, err := fmt.Fprint(source, "\n\n"); err != nil { return err } if err := f.renderImports(source); err != nil { diff --git a/vendor/github.com/dave/jennifer/jen/reserved.go b/vendor/github.com/dave/jennifer/jen/reserved.go new file mode 100644 index 000000000..457668eff --- /dev/null +++ b/vendor/github.com/dave/jennifer/jen/reserved.go @@ -0,0 +1,20 @@ +package jen + +var reserved = []string{ + /* keywords */ + "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", + /* predeclared */ + "bool", "byte", "complex64", "complex128", "error", "float32", "float64", "int", "int8", "int16", "int32", "int64", "rune", "string", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "true", "false", "iota", "nil", "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", "panic", "print", "println", "real", "recover", + /* common variables */ + "err", +} + +// IsReservedWord returns if this is a reserved word in go +func IsReservedWord(alias string) bool { + for _, name := range reserved { + if alias == name { + return true + } + } + return false +} diff --git a/vendor/github.com/dave/jennifer/jen/statement.go b/vendor/github.com/dave/jennifer/jen/statement.go index 41f14b11c..aa9ec4977 100644 --- a/vendor/github.com/dave/jennifer/jen/statement.go +++ b/vendor/github.com/dave/jennifer/jen/statement.go @@ -71,9 +71,22 @@ func (s *Statement) render(f *File, w io.Writer, _ *Statement) error { // Render renders the Statement to the provided writer. func (s *Statement) Render(writer io.Writer) error { - f := NewFile("") + return s.RenderWithFile(writer, NewFile("")) +} + +// GoString renders the Statement for testing. Any error will cause a panic. +func (s *Statement) GoString() string { + buf := bytes.Buffer{} + if err := s.Render(&buf); err != nil { + panic(err) + } + return buf.String() +} + +// RenderWithFile renders the Statement to the provided writer, using imports from the provided file. +func (s *Statement) RenderWithFile(writer io.Writer, file *File) error { buf := &bytes.Buffer{} - if err := s.render(f, buf, nil); err != nil { + if err := s.render(file, buf, nil); err != nil { return err } b, err := format.Source(buf.Bytes()) @@ -86,11 +99,3 @@ func (s *Statement) Render(writer io.Writer) error { return nil } -// GoString renders the Statement for testing. Any error will cause a panic. -func (s *Statement) GoString() string { - buf := bytes.Buffer{} - if err := s.Render(&buf); err != nil { - panic(err) - } - return buf.String() -} diff --git a/vendor/github.com/dave/jennifer/jen/tokens.go b/vendor/github.com/dave/jennifer/jen/tokens.go index 328f36a03..287a3cd63 100644 --- a/vendor/github.com/dave/jennifer/jen/tokens.go +++ b/vendor/github.com/dave/jennifer/jen/tokens.go @@ -30,8 +30,8 @@ type token struct { func (t token) isNull(f *File) bool { if t.typ == packageToken { - // package token is null if the path is the local package path - return f.isLocal(t.content.(string)) + // package token is null if the path is a dot-import or the local package path + return f.isDotImport(t.content.(string)) || f.isLocal(t.content.(string)) } return t.typ == nullToken } diff --git a/vendor/modules.txt b/vendor/modules.txt index 28b4463bf..3f61cd914 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -109,8 +109,8 @@ github.com/daixiang0/gci/pkg/parse github.com/daixiang0/gci/pkg/section github.com/daixiang0/gci/pkg/specificity github.com/daixiang0/gci/pkg/utils -# github.com/dave/jennifer v1.0.2 -## explicit +# github.com/dave/jennifer v1.4.1 +## explicit; go 1.15 github.com/dave/jennifer/jen # github.com/davecgh/go-spew v1.1.1 ## explicit From 7039660f3bd5b308e83caa4da451cf63ce30ef18 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:15:15 +0200 Subject: [PATCH 09/31] gomod: Update github.com/golang-jwt/jwt to v5 --- go.mod | 2 +- go.sum | 4 +- .../golang-jwt/jwt/MIGRATION_GUIDE.md | 22 -- vendor/github.com/golang-jwt/jwt/README.md | 113 ------- vendor/github.com/golang-jwt/jwt/claims.go | 146 -------- vendor/github.com/golang-jwt/jwt/errors.go | 59 ---- .../github.com/golang-jwt/jwt/map_claims.go | 120 ------- vendor/github.com/golang-jwt/jwt/parser.go | 148 -------- .../golang-jwt/jwt/signing_method.go | 35 -- vendor/github.com/golang-jwt/jwt/token.go | 104 ------ .../golang-jwt/jwt/{ => v5}/.gitignore | 0 .../golang-jwt/jwt/{ => v5}/LICENSE | 0 .../golang-jwt/jwt/v5/MIGRATION_GUIDE.md | 195 +++++++++++ vendor/github.com/golang-jwt/jwt/v5/README.md | 167 +++++++++ .../github.com/golang-jwt/jwt/v5/SECURITY.md | 19 ++ .../jwt/{ => v5}/VERSION_HISTORY.md | 18 +- vendor/github.com/golang-jwt/jwt/v5/claims.go | 16 + .../github.com/golang-jwt/jwt/{ => v5}/doc.go | 0 .../golang-jwt/jwt/{ => v5}/ecdsa.go | 30 +- .../golang-jwt/jwt/{ => v5}/ecdsa_utils.go | 8 +- .../golang-jwt/jwt/{ => v5}/ed25519.go | 48 ++- .../golang-jwt/jwt/{ => v5}/ed25519_utils.go | 8 +- vendor/github.com/golang-jwt/jwt/v5/errors.go | 49 +++ .../golang-jwt/jwt/v5/errors_go1_20.go | 47 +++ .../golang-jwt/jwt/v5/errors_go_other.go | 78 +++++ .../golang-jwt/jwt/{ => v5}/hmac.go | 41 ++- .../golang-jwt/jwt/v5/map_claims.go | 109 ++++++ .../golang-jwt/jwt/{ => v5}/none.go | 20 +- vendor/github.com/golang-jwt/jwt/v5/parser.go | 238 +++++++++++++ .../golang-jwt/jwt/v5/parser_option.go | 128 +++++++ .../golang-jwt/jwt/v5/registered_claims.go | 63 ++++ .../github.com/golang-jwt/jwt/{ => v5}/rsa.go | 28 +- .../golang-jwt/jwt/{ => v5}/rsa_pss.go | 29 +- .../golang-jwt/jwt/{ => v5}/rsa_utils.go | 20 +- .../golang-jwt/jwt/v5/signing_method.go | 49 +++ .../golang-jwt/jwt/v5/staticcheck.conf | 1 + vendor/github.com/golang-jwt/jwt/v5/token.go | 100 ++++++ .../golang-jwt/jwt/v5/token_option.go | 5 + vendor/github.com/golang-jwt/jwt/v5/types.go | 149 +++++++++ .../github.com/golang-jwt/jwt/v5/validator.go | 316 ++++++++++++++++++ vendor/modules.txt | 6 +- 41 files changed, 1857 insertions(+), 881 deletions(-) delete mode 100644 vendor/github.com/golang-jwt/jwt/MIGRATION_GUIDE.md delete mode 100644 vendor/github.com/golang-jwt/jwt/README.md delete mode 100644 vendor/github.com/golang-jwt/jwt/claims.go delete mode 100644 vendor/github.com/golang-jwt/jwt/errors.go delete mode 100644 vendor/github.com/golang-jwt/jwt/map_claims.go delete mode 100644 vendor/github.com/golang-jwt/jwt/parser.go delete mode 100644 vendor/github.com/golang-jwt/jwt/signing_method.go delete mode 100644 vendor/github.com/golang-jwt/jwt/token.go rename vendor/github.com/golang-jwt/jwt/{ => v5}/.gitignore (100%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/LICENSE (100%) create mode 100644 vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md create mode 100644 vendor/github.com/golang-jwt/jwt/v5/README.md create mode 100644 vendor/github.com/golang-jwt/jwt/v5/SECURITY.md rename vendor/github.com/golang-jwt/jwt/{ => v5}/VERSION_HISTORY.md (94%) create mode 100644 vendor/github.com/golang-jwt/jwt/v5/claims.go rename vendor/github.com/golang-jwt/jwt/{ => v5}/doc.go (100%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/ecdsa.go (83%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/ecdsa_utils.go (81%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/ed25519.go (52%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/ed25519_utils.go (80%) create mode 100644 vendor/github.com/golang-jwt/jwt/v5/errors.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/errors_go1_20.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go rename vendor/github.com/golang-jwt/jwt/{ => v5}/hmac.go (53%) create mode 100644 vendor/github.com/golang-jwt/jwt/v5/map_claims.go rename vendor/github.com/golang-jwt/jwt/{ => v5}/none.go (68%) create mode 100644 vendor/github.com/golang-jwt/jwt/v5/parser.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/parser_option.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/registered_claims.go rename vendor/github.com/golang-jwt/jwt/{ => v5}/rsa.go (77%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/rsa_pss.go (83%) rename vendor/github.com/golang-jwt/jwt/{ => v5}/rsa_utils.go (69%) create mode 100644 vendor/github.com/golang-jwt/jwt/v5/signing_method.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf create mode 100644 vendor/github.com/golang-jwt/jwt/v5/token.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/token_option.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/types.go create mode 100644 vendor/github.com/golang-jwt/jwt/v5/validator.go diff --git a/go.mod b/go.mod index e4dec0f79..8802a1988 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/go-kivik/kivik/v3 v3.2.3 github.com/go-pg/pg v6.14.5+incompatible github.com/go-redis/redis/v7 v7.4.1 - github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golangci/golangci-lint v1.51.2 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index 1e19d86d9..a6cb6b0bf 100644 --- a/go.sum +++ b/go.sum @@ -226,8 +226,8 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 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= diff --git a/vendor/github.com/golang-jwt/jwt/MIGRATION_GUIDE.md b/vendor/github.com/golang-jwt/jwt/MIGRATION_GUIDE.md deleted file mode 100644 index c4efbd2a8..000000000 --- a/vendor/github.com/golang-jwt/jwt/MIGRATION_GUIDE.md +++ /dev/null @@ -1,22 +0,0 @@ -## Migration Guide (v3.2.1) - -Starting from [v3.2.1](https://github.com/golang-jwt/jwt/releases/tag/v3.2.1]), the import path has changed from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`. Future releases will be using the `github.com/golang-jwt/jwt` import path and continue the existing versioning scheme of `v3.x.x+incompatible`. Backwards-compatible patches and fixes will be done on the `v3` release branch, where as new build-breaking features will be developed in a `v4` release, possibly including a SIV-style import path. - -### go.mod replacement - -In a first step, the easiest way is to use `go mod edit` to issue a replacement. - -``` -go mod edit -replace github.com/dgrijalva/jwt-go=github.com/golang-jwt/jwt@v3.2.1+incompatible -go mod tidy -``` - -This will still keep the old import path in your code but replace it with the new package and also introduce a new indirect dependency to `github.com/golang-jwt/jwt`. Try to compile your project; it should still work. - -### Cleanup - -If your code still consistently builds, you can replace all occurences of `github.com/dgrijalva/jwt-go` with `github.com/golang-jwt/jwt`, either manually or by using tools such as `sed`. Finally, the `replace` directive in the `go.mod` file can be removed. - -## Older releases (before v3.2.0) - -The original migration guide for older releases can be found at https://github.com/dgrijalva/jwt-go/blob/master/MIGRATION_GUIDE.md. \ No newline at end of file diff --git a/vendor/github.com/golang-jwt/jwt/README.md b/vendor/github.com/golang-jwt/jwt/README.md deleted file mode 100644 index 9b653e46b..000000000 --- a/vendor/github.com/golang-jwt/jwt/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# jwt-go - -[![build](https://github.com/golang-jwt/jwt/actions/workflows/build.yml/badge.svg)](https://github.com/golang-jwt/jwt/actions/workflows/build.yml) -[![Go Reference](https://pkg.go.dev/badge/github.com/golang-jwt/jwt.svg)](https://pkg.go.dev/github.com/golang-jwt/jwt) - -A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](https://datatracker.ietf.org/doc/html/rfc7519). - -**IMPORT PATH CHANGE:** Starting from [v3.2.1](https://github.com/golang-jwt/jwt/releases/tag/v3.2.1), the import path has changed from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`. After the original author of the library suggested migrating the maintenance of `jwt-go`, a dedicated team of open source maintainers decided to clone the existing library into this repository. See [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a detailed discussion on this topic. - -Future releases will be using the `github.com/golang-jwt/jwt` import path and continue the existing versioning scheme of `v3.x.x+incompatible`. Backwards-compatible patches and fixes will be done on the `v3` release branch, where as new build-breaking features will be developed in a `v4` release, possibly including a SIV-style import path. - -**SECURITY NOTICE:** Some older versions of Go have a security issue in the crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue [dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more detail. - -**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided. - -### Supported Go versions - -Our support of Go versions is aligned with Go's [version release policy](https://golang.org/doc/devel/release#policy). -So we will support a major version of Go until there are two newer major releases. -We no longer support building jwt-go with unsupported Go versions, as these contain security vulnerabilities -which will not be fixed. - -## What the heck is a JWT? - -JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens. - -In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648) encoded. The last part is the signature, encoded the same way. - -The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used. - -The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about reserved keys and the proper way to add your own. - -## What's in the box? - -This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own. - -## Examples - -See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt) for examples of usage: - -* [Simple example of parsing and validating a token](https://pkg.go.dev/github.com/golang-jwt/jwt#example-Parse-Hmac) -* [Simple example of building and signing a token](https://pkg.go.dev/github.com/golang-jwt/jwt#example-New-Hmac) -* [Directory of Examples](https://pkg.go.dev/github.com/golang-jwt/jwt#pkg-examples) - -## Extensions - -This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. - -Here's an example of an extension that integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS): https://github.com/someone1/gcp-jwt-go - -## Compliance - -This library was last reviewed to comply with [RTF 7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few notable differences: - -* In order to protect against accidental use of [Unsecured JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key. - -## Project Status & Versioning - -This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason). - -This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `main`. Periodically, versions will be tagged from `main`. You can find all the releases on [the project releases page](https://github.com/golang-jwt/jwt/releases). - -While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/golang-jwt/jwt.v3`. It will do the right thing WRT semantic versioning. - -**BREAKING CHANGES:*** -* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code. - -## Usage Tips - -### Signing vs Encryption - -A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data: - -* The author of the token was in the possession of the signing secret -* The data has not been modified since it was signed - -It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library. - -### Choosing a Signing Method - -There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric. - -Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation. - -Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification. - -### Signing Methods and Key Types - -Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones: - -* The [HMAC signing method](https://pkg.go.dev/github.com/golang-jwt/jwt#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation -* The [RSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation -* The [ECDSA signing method](https://pkg.go.dev/github.com/golang-jwt/jwt#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation - -### JWT and OAuth - -It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication. - -Without going too far down the rabbit hole, here's a description of the interaction of these technologies: - -* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth. -* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token. -* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL. - -### Troubleshooting - -This library uses descriptive error messages whenever possible. If you are not getting the expected result, have a look at the errors. The most common place people get stuck is providing the correct type of key to the parser. See the above section on signing methods and key types. - -## More - -Documentation can be found [on pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt). - -The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation. diff --git a/vendor/github.com/golang-jwt/jwt/claims.go b/vendor/github.com/golang-jwt/jwt/claims.go deleted file mode 100644 index f1dba3cb9..000000000 --- a/vendor/github.com/golang-jwt/jwt/claims.go +++ /dev/null @@ -1,146 +0,0 @@ -package jwt - -import ( - "crypto/subtle" - "fmt" - "time" -) - -// For a type to be a Claims object, it must just have a Valid method that determines -// if the token is invalid for any supported reason -type Claims interface { - Valid() error -} - -// Structured version of Claims Section, as referenced at -// https://tools.ietf.org/html/rfc7519#section-4.1 -// See examples for how to use this with your own claim types -type StandardClaims struct { - Audience string `json:"aud,omitempty"` - ExpiresAt int64 `json:"exp,omitempty"` - Id string `json:"jti,omitempty"` - IssuedAt int64 `json:"iat,omitempty"` - Issuer string `json:"iss,omitempty"` - NotBefore int64 `json:"nbf,omitempty"` - Subject string `json:"sub,omitempty"` -} - -// Validates time based claims "exp, iat, nbf". -// There is no accounting for clock skew. -// As well, if any of the above claims are not in the token, it will still -// be considered a valid claim. -func (c StandardClaims) Valid() error { - vErr := new(ValidationError) - now := TimeFunc().Unix() - - // The claims below are optional, by default, so if they are set to the - // default value in Go, let's not fail the verification for them. - if !c.VerifyExpiresAt(now, false) { - delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0)) - vErr.Inner = fmt.Errorf("token is expired by %v", delta) - vErr.Errors |= ValidationErrorExpired - } - - if !c.VerifyIssuedAt(now, false) { - vErr.Inner = fmt.Errorf("Token used before issued") - vErr.Errors |= ValidationErrorIssuedAt - } - - if !c.VerifyNotBefore(now, false) { - vErr.Inner = fmt.Errorf("token is not valid yet") - vErr.Errors |= ValidationErrorNotValidYet - } - - if vErr.valid() { - return nil - } - - return vErr -} - -// Compares the aud claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool { - return verifyAud([]string{c.Audience}, cmp, req) -} - -// Compares the exp claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool { - return verifyExp(c.ExpiresAt, cmp, req) -} - -// Compares the iat claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool { - return verifyIat(c.IssuedAt, cmp, req) -} - -// Compares the iss claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool { - return verifyIss(c.Issuer, cmp, req) -} - -// Compares the nbf claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool { - return verifyNbf(c.NotBefore, cmp, req) -} - -// ----- helpers - -func verifyAud(aud []string, cmp string, required bool) bool { - if len(aud) == 0 { - return !required - } - // use a var here to keep constant time compare when looping over a number of claims - result := false - - var stringClaims string - for _, a := range aud { - if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 { - result = true - } - stringClaims = stringClaims + a - } - - // case where "" is sent in one or many aud claims - if len(stringClaims) == 0 { - return !required - } - - return result -} - -func verifyExp(exp int64, now int64, required bool) bool { - if exp == 0 { - return !required - } - return now <= exp -} - -func verifyIat(iat int64, now int64, required bool) bool { - if iat == 0 { - return !required - } - return now >= iat -} - -func verifyIss(iss string, cmp string, required bool) bool { - if iss == "" { - return !required - } - if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 { - return true - } else { - return false - } -} - -func verifyNbf(nbf int64, now int64, required bool) bool { - if nbf == 0 { - return !required - } - return now >= nbf -} diff --git a/vendor/github.com/golang-jwt/jwt/errors.go b/vendor/github.com/golang-jwt/jwt/errors.go deleted file mode 100644 index 1c93024aa..000000000 --- a/vendor/github.com/golang-jwt/jwt/errors.go +++ /dev/null @@ -1,59 +0,0 @@ -package jwt - -import ( - "errors" -) - -// Error constants -var ( - ErrInvalidKey = errors.New("key is invalid") - ErrInvalidKeyType = errors.New("key is of invalid type") - ErrHashUnavailable = errors.New("the requested hash function is unavailable") -) - -// The errors that might occur when parsing and validating a token -const ( - ValidationErrorMalformed uint32 = 1 << iota // Token is malformed - ValidationErrorUnverifiable // Token could not be verified because of signing problems - ValidationErrorSignatureInvalid // Signature validation failed - - // Standard Claim validation errors - ValidationErrorAudience // AUD validation failed - ValidationErrorExpired // EXP validation failed - ValidationErrorIssuedAt // IAT validation failed - ValidationErrorIssuer // ISS validation failed - ValidationErrorNotValidYet // NBF validation failed - ValidationErrorId // JTI validation failed - ValidationErrorClaimsInvalid // Generic claims validation error -) - -// Helper for constructing a ValidationError with a string error message -func NewValidationError(errorText string, errorFlags uint32) *ValidationError { - return &ValidationError{ - text: errorText, - Errors: errorFlags, - } -} - -// The error from Parse if token is not valid -type ValidationError struct { - Inner error // stores the error returned by external dependencies, i.e.: KeyFunc - Errors uint32 // bitfield. see ValidationError... constants - text string // errors that do not have a valid error just have text -} - -// Validation error is an error type -func (e ValidationError) Error() string { - if e.Inner != nil { - return e.Inner.Error() - } else if e.text != "" { - return e.text - } else { - return "token is invalid" - } -} - -// No errors -func (e *ValidationError) valid() bool { - return e.Errors == 0 -} diff --git a/vendor/github.com/golang-jwt/jwt/map_claims.go b/vendor/github.com/golang-jwt/jwt/map_claims.go deleted file mode 100644 index 72c79f92e..000000000 --- a/vendor/github.com/golang-jwt/jwt/map_claims.go +++ /dev/null @@ -1,120 +0,0 @@ -package jwt - -import ( - "encoding/json" - "errors" - // "fmt" -) - -// Claims type that uses the map[string]interface{} for JSON decoding -// This is the default claims type if you don't supply one -type MapClaims map[string]interface{} - -// VerifyAudience Compares the aud claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyAudience(cmp string, req bool) bool { - var aud []string - switch v := m["aud"].(type) { - case string: - aud = append(aud, v) - case []string: - aud = v - case []interface{}: - for _, a := range v { - vs, ok := a.(string) - if !ok { - return false - } - aud = append(aud, vs) - } - } - return verifyAud(aud, cmp, req) -} - -// Compares the exp claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool { - exp, ok := m["exp"] - if !ok { - return !req - } - switch expType := exp.(type) { - case float64: - return verifyExp(int64(expType), cmp, req) - case json.Number: - v, _ := expType.Int64() - return verifyExp(v, cmp, req) - } - return false -} - -// Compares the iat claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool { - iat, ok := m["iat"] - if !ok { - return !req - } - switch iatType := iat.(type) { - case float64: - return verifyIat(int64(iatType), cmp, req) - case json.Number: - v, _ := iatType.Int64() - return verifyIat(v, cmp, req) - } - return false -} - -// Compares the iss claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyIssuer(cmp string, req bool) bool { - iss, _ := m["iss"].(string) - return verifyIss(iss, cmp, req) -} - -// Compares the nbf claim against cmp. -// If required is false, this method will return true if the value matches or is unset -func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool { - nbf, ok := m["nbf"] - if !ok { - return !req - } - switch nbfType := nbf.(type) { - case float64: - return verifyNbf(int64(nbfType), cmp, req) - case json.Number: - v, _ := nbfType.Int64() - return verifyNbf(v, cmp, req) - } - return false -} - -// Validates time based claims "exp, iat, nbf". -// There is no accounting for clock skew. -// As well, if any of the above claims are not in the token, it will still -// be considered a valid claim. -func (m MapClaims) Valid() error { - vErr := new(ValidationError) - now := TimeFunc().Unix() - - if !m.VerifyExpiresAt(now, false) { - vErr.Inner = errors.New("Token is expired") - vErr.Errors |= ValidationErrorExpired - } - - if !m.VerifyIssuedAt(now, false) { - vErr.Inner = errors.New("Token used before issued") - vErr.Errors |= ValidationErrorIssuedAt - } - - if !m.VerifyNotBefore(now, false) { - vErr.Inner = errors.New("Token is not valid yet") - vErr.Errors |= ValidationErrorNotValidYet - } - - if vErr.valid() { - return nil - } - - return vErr -} diff --git a/vendor/github.com/golang-jwt/jwt/parser.go b/vendor/github.com/golang-jwt/jwt/parser.go deleted file mode 100644 index d6901d9ad..000000000 --- a/vendor/github.com/golang-jwt/jwt/parser.go +++ /dev/null @@ -1,148 +0,0 @@ -package jwt - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" -) - -type Parser struct { - ValidMethods []string // If populated, only these methods will be considered valid - UseJSONNumber bool // Use JSON Number format in JSON decoder - SkipClaimsValidation bool // Skip claims validation during token parsing -} - -// Parse, validate, and return a token. -// keyFunc will receive the parsed token and should return the key for validating. -// If everything is kosher, err will be nil -func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { - return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc) -} - -func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { - token, parts, err := p.ParseUnverified(tokenString, claims) - if err != nil { - return token, err - } - - // Verify signing method is in the required set - if p.ValidMethods != nil { - var signingMethodValid = false - var alg = token.Method.Alg() - for _, m := range p.ValidMethods { - if m == alg { - signingMethodValid = true - break - } - } - if !signingMethodValid { - // signing method is not in the listed set - return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid) - } - } - - // Lookup key - var key interface{} - if keyFunc == nil { - // keyFunc was not provided. short circuiting validation - return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable) - } - if key, err = keyFunc(token); err != nil { - // keyFunc returned an error - if ve, ok := err.(*ValidationError); ok { - return token, ve - } - return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable} - } - - vErr := &ValidationError{} - - // Validate Claims - if !p.SkipClaimsValidation { - if err := token.Claims.Valid(); err != nil { - - // If the Claims Valid returned an error, check if it is a validation error, - // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set - if e, ok := err.(*ValidationError); !ok { - vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid} - } else { - vErr = e - } - } - } - - // Perform validation - token.Signature = parts[2] - if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil { - vErr.Inner = err - vErr.Errors |= ValidationErrorSignatureInvalid - } - - if vErr.valid() { - token.Valid = true - return token, nil - } - - return token, vErr -} - -// WARNING: Don't use this method unless you know what you're doing -// -// This method parses the token but doesn't validate the signature. It's only -// ever useful in cases where you know the signature is valid (because it has -// been checked previously in the stack) and you want to extract values from -// it. -func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) { - parts = strings.Split(tokenString, ".") - if len(parts) != 3 { - return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed) - } - - token = &Token{Raw: tokenString} - - // parse Header - var headerBytes []byte - if headerBytes, err = DecodeSegment(parts[0]); err != nil { - if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") { - return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed) - } - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - if err = json.Unmarshal(headerBytes, &token.Header); err != nil { - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - - // parse Claims - var claimBytes []byte - token.Claims = claims - - if claimBytes, err = DecodeSegment(parts[1]); err != nil { - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) - if p.UseJSONNumber { - dec.UseNumber() - } - // JSON Decode. Special case for map type to avoid weird pointer behavior - if c, ok := token.Claims.(MapClaims); ok { - err = dec.Decode(&c) - } else { - err = dec.Decode(&claims) - } - // Handle decode error - if err != nil { - return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed} - } - - // Lookup signature method - if method, ok := token.Header["alg"].(string); ok { - if token.Method = GetSigningMethod(method); token.Method == nil { - return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable) - } - } else { - return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable) - } - - return token, parts, nil -} diff --git a/vendor/github.com/golang-jwt/jwt/signing_method.go b/vendor/github.com/golang-jwt/jwt/signing_method.go deleted file mode 100644 index ed1f212b2..000000000 --- a/vendor/github.com/golang-jwt/jwt/signing_method.go +++ /dev/null @@ -1,35 +0,0 @@ -package jwt - -import ( - "sync" -) - -var signingMethods = map[string]func() SigningMethod{} -var signingMethodLock = new(sync.RWMutex) - -// Implement SigningMethod to add new methods for signing or verifying tokens. -type SigningMethod interface { - Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid - Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error - Alg() string // returns the alg identifier for this method (example: 'HS256') -} - -// Register the "alg" name and a factory function for signing method. -// This is typically done during init() in the method's implementation -func RegisterSigningMethod(alg string, f func() SigningMethod) { - signingMethodLock.Lock() - defer signingMethodLock.Unlock() - - signingMethods[alg] = f -} - -// Get a signing method from an "alg" string -func GetSigningMethod(alg string) (method SigningMethod) { - signingMethodLock.RLock() - defer signingMethodLock.RUnlock() - - if methodF, ok := signingMethods[alg]; ok { - method = methodF() - } - return -} diff --git a/vendor/github.com/golang-jwt/jwt/token.go b/vendor/github.com/golang-jwt/jwt/token.go deleted file mode 100644 index 6b30ced12..000000000 --- a/vendor/github.com/golang-jwt/jwt/token.go +++ /dev/null @@ -1,104 +0,0 @@ -package jwt - -import ( - "encoding/base64" - "encoding/json" - "strings" - "time" -) - -// TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time). -// You can override it to use another time value. This is useful for testing or if your -// server uses a different time zone than your tokens. -var TimeFunc = time.Now - -// Parse methods use this callback function to supply -// the key for verification. The function receives the parsed, -// but unverified Token. This allows you to use properties in the -// Header of the token (such as `kid`) to identify which key to use. -type Keyfunc func(*Token) (interface{}, error) - -// A JWT Token. Different fields will be used depending on whether you're -// creating or parsing/verifying a token. -type Token struct { - Raw string // The raw token. Populated when you Parse a token - Method SigningMethod // The signing method used or to be used - Header map[string]interface{} // The first segment of the token - Claims Claims // The second segment of the token - Signature string // The third segment of the token. Populated when you Parse a token - Valid bool // Is the token valid? Populated when you Parse/Verify a token -} - -// Create a new Token. Takes a signing method -func New(method SigningMethod) *Token { - return NewWithClaims(method, MapClaims{}) -} - -func NewWithClaims(method SigningMethod, claims Claims) *Token { - return &Token{ - Header: map[string]interface{}{ - "typ": "JWT", - "alg": method.Alg(), - }, - Claims: claims, - Method: method, - } -} - -// Get the complete, signed token -func (t *Token) SignedString(key interface{}) (string, error) { - var sig, sstr string - var err error - if sstr, err = t.SigningString(); err != nil { - return "", err - } - if sig, err = t.Method.Sign(sstr, key); err != nil { - return "", err - } - return strings.Join([]string{sstr, sig}, "."), nil -} - -// Generate the signing string. This is the -// most expensive part of the whole deal. Unless you -// need this for something special, just go straight for -// the SignedString. -func (t *Token) SigningString() (string, error) { - var err error - parts := make([]string, 2) - for i := range parts { - var jsonValue []byte - if i == 0 { - if jsonValue, err = json.Marshal(t.Header); err != nil { - return "", err - } - } else { - if jsonValue, err = json.Marshal(t.Claims); err != nil { - return "", err - } - } - - parts[i] = EncodeSegment(jsonValue) - } - return strings.Join(parts, "."), nil -} - -// Parse, validate, and return a token. -// keyFunc will receive the parsed token and should return the key for validating. -// If everything is kosher, err will be nil -func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { - return new(Parser).Parse(tokenString, keyFunc) -} - -func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { - return new(Parser).ParseWithClaims(tokenString, claims, keyFunc) -} - -// Encode JWT specific base64url encoding with padding stripped -func EncodeSegment(seg []byte) string { - return base64.RawURLEncoding.EncodeToString(seg) -} - -// Decode JWT specific base64url encoding with padding stripped -func DecodeSegment(seg string) ([]byte, error) { - return base64.RawURLEncoding.DecodeString(seg) -} diff --git a/vendor/github.com/golang-jwt/jwt/.gitignore b/vendor/github.com/golang-jwt/jwt/v5/.gitignore similarity index 100% rename from vendor/github.com/golang-jwt/jwt/.gitignore rename to vendor/github.com/golang-jwt/jwt/v5/.gitignore diff --git a/vendor/github.com/golang-jwt/jwt/LICENSE b/vendor/github.com/golang-jwt/jwt/v5/LICENSE similarity index 100% rename from vendor/github.com/golang-jwt/jwt/LICENSE rename to vendor/github.com/golang-jwt/jwt/v5/LICENSE diff --git a/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md b/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md new file mode 100644 index 000000000..ff9c57e1d --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md @@ -0,0 +1,195 @@ +# Migration Guide (v5.0.0) + +Version `v5` contains a major rework of core functionalities in the `jwt-go` +library. This includes support for several validation options as well as a +re-design of the `Claims` interface. Lastly, we reworked how errors work under +the hood, which should provide a better overall developer experience. + +Starting from [v5.0.0](https://github.com/golang-jwt/jwt/releases/tag/v5.0.0), +the import path will be: + + "github.com/golang-jwt/jwt/v5" + +For most users, changing the import path *should* suffice. However, since we +intentionally changed and cleaned some of the public API, existing programs +might need to be updated. The following sections describe significant changes +and corresponding updates for existing programs. + +## Parsing and Validation Options + +Under the hood, a new `Validator` struct takes care of validating the claims. A +long awaited feature has been the option to fine-tune the validation of tokens. +This is now possible with several `ParserOption` functions that can be appended +to most `Parse` functions, such as `ParseWithClaims`. The most important options +and changes are: + * Added `WithLeeway` to support specifying the leeway that is allowed when + validating time-based claims, such as `exp` or `nbf`. + * Changed default behavior to not check the `iat` claim. Usage of this claim + is OPTIONAL according to the JWT RFC. The claim itself is also purely + informational according to the RFC, so a strict validation failure is not + recommended. If you want to check for sensible values in these claims, + please use the `WithIssuedAt` parser option. + * Added `WithAudience`, `WithSubject` and `WithIssuer` to support checking for + expected `aud`, `sub` and `iss`. + * Added `WithStrictDecoding` and `WithPaddingAllowed` options to allow + previously global settings to enable base64 strict encoding and the parsing + of base64 strings with padding. The latter is strictly speaking against the + standard, but unfortunately some of the major identity providers issue some + of these incorrect tokens. Both options are disabled by default. + +## Changes to the `Claims` interface + +### Complete Restructuring + +Previously, the claims interface was satisfied with an implementation of a +`Valid() error` function. This had several issues: + * The different claim types (struct claims, map claims, etc.) then contained + similar (but not 100 % identical) code of how this validation was done. This + lead to a lot of (almost) duplicate code and was hard to maintain + * It was not really semantically close to what a "claim" (or a set of claims) + really is; which is a list of defined key/value pairs with a certain + semantic meaning. + +Since all the validation functionality is now extracted into the validator, all +`VerifyXXX` and `Valid` functions have been removed from the `Claims` interface. +Instead, the interface now represents a list of getters to retrieve values with +a specific meaning. This allows us to completely decouple the validation logic +with the underlying storage representation of the claim, which could be a +struct, a map or even something stored in a database. + +```go +type Claims interface { + GetExpirationTime() (*NumericDate, error) + GetIssuedAt() (*NumericDate, error) + GetNotBefore() (*NumericDate, error) + GetIssuer() (string, error) + GetSubject() (string, error) + GetAudience() (ClaimStrings, error) +} +``` + +Users that previously directly called the `Valid` function on their claims, +e.g., to perform validation independently of parsing/verifying a token, can now +use the `jwt.NewValidator` function to create a `Validator` independently of the +`Parser`. + +```go +var v = jwt.NewValidator(jwt.WithLeeway(5*time.Second)) +v.Validate(myClaims) +``` + +### Supported Claim Types and Removal of `StandardClaims` + +The two standard claim types supported by this library, `MapClaims` and +`RegisteredClaims` both implement the necessary functions of this interface. The +old `StandardClaims` struct, which has already been deprecated in `v4` is now +removed. + +Users using custom claims, in most cases, will not experience any changes in the +behavior as long as they embedded `RegisteredClaims`. If they created a new +claim type from scratch, they now need to implemented the proper getter +functions. + +### Migrating Application Specific Logic of the old `Valid` + +Previously, users could override the `Valid` method in a custom claim, for +example to extend the validation with application-specific claims. However, this +was always very dangerous, since once could easily disable the standard +validation and signature checking. + +In order to avoid that, while still supporting the use-case, a new +`ClaimsValidator` interface has been introduced. This interface consists of the +`Validate() error` function. If the validator sees, that a `Claims` struct +implements this interface, the errors returned to the `Validate` function will +be *appended* to the regular standard validation. It is not possible to disable +the standard validation anymore (even only by accident). + +Usage examples can be found in [example_test.go](./example_test.go), to build +claims structs like the following. + +```go +// MyCustomClaims includes all registered claims, plus Foo. +type MyCustomClaims struct { + Foo string `json:"foo"` + jwt.RegisteredClaims +} + +// Validate can be used to execute additional application-specific claims +// validation. +func (m MyCustomClaims) Validate() error { + if m.Foo != "bar" { + return errors.New("must be foobar") + } + + return nil +} +``` + +## Changes to the `Token` and `Parser` struct + +The previously global functions `DecodeSegment` and `EncodeSegment` were moved +to the `Parser` and `Token` struct respectively. This will allow us in the +future to configure the behavior of these two based on options supplied on the +parser or the token (creation). This also removes two previously global +variables and moves them to parser options `WithStrictDecoding` and +`WithPaddingAllowed`. + +In order to do that, we had to adjust the way signing methods work. Previously +they were given a base64 encoded signature in `Verify` and were expected to +return a base64 encoded version of the signature in `Sign`, both as a `string`. +However, this made it necessary to have `DecodeSegment` and `EncodeSegment` +global and was a less than perfect design because we were repeating +encoding/decoding steps for all signing methods. Now, `Sign` and `Verify` +operate on a decoded signature as a `[]byte`, which feels more natural for a +cryptographic operation anyway. Lastly, `Parse` and `SignedString` take care of +the final encoding/decoding part. + +In addition to that, we also changed the `Signature` field on `Token` from a +`string` to `[]byte` and this is also now populated with the decoded form. This +is also more consistent, because the other parts of the JWT, mainly `Header` and +`Claims` were already stored in decoded form in `Token`. Only the signature was +stored in base64 encoded form, which was redundant with the information in the +`Raw` field, which contains the complete token as base64. + +```go +type Token struct { + Raw string // Raw contains the raw token + Method SigningMethod // Method is the signing method used or to be used + Header map[string]interface{} // Header is the first segment of the token in decoded form + Claims Claims // Claims is the second segment of the token in decoded form + Signature []byte // Signature is the third segment of the token in decoded form + Valid bool // Valid specifies if the token is valid +} +``` + +Most (if not all) of these changes should not impact the normal usage of this +library. Only users directly accessing the `Signature` field as well as +developers of custom signing methods should be affected. + +# Migration Guide (v4.0.0) + +Starting from [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0), +the import path will be: + + "github.com/golang-jwt/jwt/v4" + +The `/v4` version will be backwards compatible with existing `v3.x.y` tags in +this repo, as well as `github.com/dgrijalva/jwt-go`. For most users this should +be a drop-in replacement, if you're having troubles migrating, please open an +issue. + +You can replace all occurrences of `github.com/dgrijalva/jwt-go` or +`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually +or by using tools such as `sed` or `gofmt`. + +And then you'd typically run: + +``` +go get github.com/golang-jwt/jwt/v4 +go mod tidy +``` + +# Older releases (before v3.2.0) + +The original migration guide for older releases can be found at +https://github.com/dgrijalva/jwt-go/blob/master/MIGRATION_GUIDE.md. diff --git a/vendor/github.com/golang-jwt/jwt/v5/README.md b/vendor/github.com/golang-jwt/jwt/v5/README.md new file mode 100644 index 000000000..964598a31 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/README.md @@ -0,0 +1,167 @@ +# jwt-go + +[![build](https://github.com/golang-jwt/jwt/actions/workflows/build.yml/badge.svg)](https://github.com/golang-jwt/jwt/actions/workflows/build.yml) +[![Go +Reference](https://pkg.go.dev/badge/github.com/golang-jwt/jwt/v5.svg)](https://pkg.go.dev/github.com/golang-jwt/jwt/v5) +[![Coverage Status](https://coveralls.io/repos/github/golang-jwt/jwt/badge.svg?branch=main)](https://coveralls.io/github/golang-jwt/jwt?branch=main) + +A [go](http://www.golang.org) (or 'golang' for search engine friendliness) +implementation of [JSON Web +Tokens](https://datatracker.ietf.org/doc/html/rfc7519). + +Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0) +this project adds Go module support, but maintains backwards compatibility with +older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`. See the +[`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information. Version +v5.0.0 introduces major improvements to the validation of tokens, but is not +entirely backwards compatible. + +> After the original author of the library suggested migrating the maintenance +> of `jwt-go`, a dedicated team of open source maintainers decided to clone the +> existing library into this repository. See +> [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a +> detailed discussion on this topic. + + +**SECURITY NOTICE:** Some older versions of Go have a security issue in the +crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue +[dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more +detail. + +**SECURITY NOTICE:** It's important that you [validate the `alg` presented is +what you +expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/). +This library attempts to make it easy to do the right thing by requiring key +types match the expected alg, but you should take the extra step to verify it in +your usage. See the examples provided. + +### Supported Go versions + +Our support of Go versions is aligned with Go's [version release +policy](https://golang.org/doc/devel/release#policy). So we will support a major +version of Go until there are two newer major releases. We no longer support +building jwt-go with unsupported Go versions, as these contain security +vulnerabilities which will not be fixed. + +## What the heck is a JWT? + +JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web +Tokens. + +In short, it's a signed JSON object that does something useful (for example, +authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is +made of three parts, separated by `.`'s. The first two parts are JSON objects, +that have been [base64url](https://datatracker.ietf.org/doc/html/rfc4648) +encoded. The last part is the signature, encoded the same way. + +The first part is called the header. It contains the necessary information for +verifying the last part, the signature. For example, which encryption method +was used for signing and what key was used. + +The part in the middle is the interesting bit. It's called the Claims and +contains the actual stuff you care about. Refer to [RFC +7519](https://datatracker.ietf.org/doc/html/rfc7519) for information about +reserved keys and the proper way to add your own. + +## What's in the box? + +This library supports the parsing and verification as well as the generation and +signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, +RSA-PSS, and ECDSA, though hooks are present for adding your own. + +## Installation Guidelines + +1. To install the jwt package, you first need to have + [Go](https://go.dev/doc/install) installed, then you can use the command + below to add `jwt-go` as a dependency in your Go program. + +```sh +go get -u github.com/golang-jwt/jwt/v5 +``` + +2. Import it in your code: + +```go +import "github.com/golang-jwt/jwt/v5" +``` + +## Usage + +A detailed usage guide, including how to sign and verify tokens can be found on +our [documentation website](https://golang-jwt.github.io/jwt/usage/create/). + +## Examples + +See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt/v5) +for examples of usage: + +* [Simple example of parsing and validating a + token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-Parse-Hmac) +* [Simple example of building and signing a + token](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-New-Hmac) +* [Directory of + Examples](https://pkg.go.dev/github.com/golang-jwt/jwt/v5#pkg-examples) + +## Compliance + +This library was last reviewed to comply with [RFC +7519](https://datatracker.ietf.org/doc/html/rfc7519) dated May 2015 with a few +notable differences: + +* In order to protect against accidental use of [Unsecured + JWTs](https://datatracker.ietf.org/doc/html/rfc7519#section-6), tokens using + `alg=none` will only be accepted if the constant + `jwt.UnsafeAllowNoneSignatureType` is provided as the key. + +## Project Status & Versioning + +This library is considered production ready. Feedback and feature requests are +appreciated. The API should be considered stable. There should be very few +backwards-incompatible changes outside of major version updates (and only with +good reason). + +This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull +requests will land on `main`. Periodically, versions will be tagged from +`main`. You can find all the releases on [the project releases +page](https://github.com/golang-jwt/jwt/releases). + +**BREAKING CHANGES:*** A full list of breaking changes is available in +`VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating +your code. + +## Extensions + +This library publishes all the necessary components for adding your own signing +methods or key functions. Simply implement the `SigningMethod` interface and +register a factory method using `RegisterSigningMethod` or provide a +`jwt.Keyfunc`. + +A common use case would be integrating with different 3rd party signature +providers, like key management services from various cloud providers or Hardware +Security Modules (HSMs) or to implement additional standards. + +| Extension | Purpose | Repo | +| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ | +| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go | +| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms | +| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc | + +*Disclaimer*: Unless otherwise specified, these integrations are maintained by +third parties and should not be considered as a primary offer by any of the +mentioned cloud providers + +## More + +Go package documentation can be found [on +pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt/v5). Additional +documentation can be found on [our project +page](https://golang-jwt.github.io/jwt/). + +The command line utility included in this project (cmd/jwt) provides a +straightforward example of token creation and parsing as well as a useful tool +for debugging your own integration. You'll also find several implementation +examples in the documentation. + +[golang-jwt](https://github.com/orgs/golang-jwt) incorporates a modified version +of the JWT logo, which is distributed under the terms of the [MIT +License](https://github.com/jsonwebtoken/jsonwebtoken.github.io/blob/master/LICENSE.txt). diff --git a/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md new file mode 100644 index 000000000..b08402c34 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +## Supported Versions + +As of February 2022 (and until this document is updated), the latest version `v4` is supported. + +## Reporting a Vulnerability + +If you think you found a vulnerability, and even if you are not sure, please report it to jwt-go-security@googlegroups.com or one of the other [golang-jwt maintainers](https://github.com/orgs/golang-jwt/people). Please try be explicit, describe steps to reproduce the security issue with code example(s). + +You will receive a response within a timely manner. If the issue is confirmed, we will do our best to release a patch as soon as possible given the complexity of the problem. + +## Public Discussions + +Please avoid publicly discussing a potential security vulnerability. + +Let's take this offline and find a solution first, this limits the potential impact as much as possible. + +We appreciate your help! diff --git a/vendor/github.com/golang-jwt/jwt/VERSION_HISTORY.md b/vendor/github.com/golang-jwt/jwt/v5/VERSION_HISTORY.md similarity index 94% rename from vendor/github.com/golang-jwt/jwt/VERSION_HISTORY.md rename to vendor/github.com/golang-jwt/jwt/v5/VERSION_HISTORY.md index 637f2ba61..b5039e49c 100644 --- a/vendor/github.com/golang-jwt/jwt/VERSION_HISTORY.md +++ b/vendor/github.com/golang-jwt/jwt/v5/VERSION_HISTORY.md @@ -1,13 +1,19 @@ -## `jwt-go` Version History +# `jwt-go` Version History -#### 3.2.2 +The following version history is kept for historic purposes. To retrieve the current changes of each version, please refer to the change-log of the specific release versions on https://github.com/golang-jwt/jwt/releases. + +## 4.0.0 + +* Introduces support for Go modules. The `v4` version will be backwards compatible with `v3.x.y`. + +## 3.2.2 * Starting from this release, we are adopting the policy to support the most 2 recent versions of Go currently available. By the time of this release, this is Go 1.15 and 1.16 ([#28](https://github.com/golang-jwt/jwt/pull/28)). * Fixed a potential issue that could occur when the verification of `exp`, `iat` or `nbf` was not required and contained invalid contents, i.e. non-numeric/date. Thanks for @thaJeztah for making us aware of that and @giorgos-f3 for originally reporting it to the formtech fork ([#40](https://github.com/golang-jwt/jwt/pull/40)). * Added support for EdDSA / ED25519 ([#36](https://github.com/golang-jwt/jwt/pull/36)). * Optimized allocations ([#33](https://github.com/golang-jwt/jwt/pull/33)). -#### 3.2.1 +## 3.2.1 * **Import Path Change**: See MIGRATION_GUIDE.md for tips on updating your code * Changed the import path from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt` @@ -113,17 +119,17 @@ It is likely the only integration change required here will be to change `func(t * Refactored the RSA implementation to be easier to read * Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM` -#### 1.0.2 +## 1.0.2 * Fixed bug in parsing public keys from certificates * Added more tests around the parsing of keys for RS256 * Code refactoring in RS256 implementation. No functional changes -#### 1.0.1 +## 1.0.1 * Fixed panic if RS256 signing method was passed an invalid key -#### 1.0.0 +## 1.0.0 * First versioned release * API stabilized diff --git a/vendor/github.com/golang-jwt/jwt/v5/claims.go b/vendor/github.com/golang-jwt/jwt/v5/claims.go new file mode 100644 index 000000000..d50ff3dad --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/claims.go @@ -0,0 +1,16 @@ +package jwt + +// Claims represent any form of a JWT Claims Set according to +// https://datatracker.ietf.org/doc/html/rfc7519#section-4. In order to have a +// common basis for validation, it is required that an implementation is able to +// supply at least the claim names provided in +// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely `exp`, +// `iat`, `nbf`, `iss`, `sub` and `aud`. +type Claims interface { + GetExpirationTime() (*NumericDate, error) + GetIssuedAt() (*NumericDate, error) + GetNotBefore() (*NumericDate, error) + GetIssuer() (string, error) + GetSubject() (string, error) + GetAudience() (ClaimStrings, error) +} diff --git a/vendor/github.com/golang-jwt/jwt/doc.go b/vendor/github.com/golang-jwt/jwt/v5/doc.go similarity index 100% rename from vendor/github.com/golang-jwt/jwt/doc.go rename to vendor/github.com/golang-jwt/jwt/v5/doc.go diff --git a/vendor/github.com/golang-jwt/jwt/ecdsa.go b/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go similarity index 83% rename from vendor/github.com/golang-jwt/jwt/ecdsa.go rename to vendor/github.com/golang-jwt/jwt/v5/ecdsa.go index 15e23435d..c929e4a02 100644 --- a/vendor/github.com/golang-jwt/jwt/ecdsa.go +++ b/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go @@ -13,7 +13,7 @@ var ( ErrECDSAVerification = errors.New("crypto/ecdsa: verification error") ) -// Implements the ECDSA family of signing methods signing methods +// SigningMethodECDSA implements the ECDSA family of signing methods. // Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification type SigningMethodECDSA struct { Name string @@ -53,24 +53,16 @@ func (m *SigningMethodECDSA) Alg() string { return m.Name } -// Implements the Verify method from SigningMethod +// Verify implements token verification for the SigningMethod. // For this verify method, key must be an ecdsa.PublicKey struct -func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error { - var err error - - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - +func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interface{}) error { // Get the key var ecdsaKey *ecdsa.PublicKey switch k := key.(type) { case *ecdsa.PublicKey: ecdsaKey = k default: - return ErrInvalidKeyType + return newError("ECDSA verify expects *ecdsa.PublicKey", ErrInvalidKeyType) } if len(sig) != 2*m.KeySize { @@ -95,21 +87,21 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa return ErrECDSAVerification } -// Implements the Sign method from SigningMethod +// Sign implements token signing for the SigningMethod. // For this signing method, key must be an ecdsa.PrivateKey struct -func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) { +func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte, error) { // Get the key var ecdsaKey *ecdsa.PrivateKey switch k := key.(type) { case *ecdsa.PrivateKey: ecdsaKey = k default: - return "", ErrInvalidKeyType + return nil, newError("ECDSA sign expects *ecdsa.PrivateKey", ErrInvalidKeyType) } // Create the hasher if !m.Hash.Available() { - return "", ErrHashUnavailable + return nil, ErrHashUnavailable } hasher := m.Hash.New() @@ -120,7 +112,7 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string curveBits := ecdsaKey.Curve.Params().BitSize if m.CurveBits != curveBits { - return "", ErrInvalidKey + return nil, ErrInvalidKey } keyBytes := curveBits / 8 @@ -135,8 +127,8 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output. s.FillBytes(out[keyBytes:]) // s is assigned to the second half of output. - return EncodeSegment(out), nil + return out, nil } else { - return "", err + return nil, err } } diff --git a/vendor/github.com/golang-jwt/jwt/ecdsa_utils.go b/vendor/github.com/golang-jwt/jwt/v5/ecdsa_utils.go similarity index 81% rename from vendor/github.com/golang-jwt/jwt/ecdsa_utils.go rename to vendor/github.com/golang-jwt/jwt/v5/ecdsa_utils.go index db9f4be7d..5700636d3 100644 --- a/vendor/github.com/golang-jwt/jwt/ecdsa_utils.go +++ b/vendor/github.com/golang-jwt/jwt/v5/ecdsa_utils.go @@ -8,11 +8,11 @@ import ( ) var ( - ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key") - ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key") + ErrNotECPublicKey = errors.New("key is not a valid ECDSA public key") + ErrNotECPrivateKey = errors.New("key is not a valid ECDSA private key") ) -// Parse PEM encoded Elliptic Curve Private Key Structure +// ParseECPrivateKeyFromPEM parses a PEM encoded Elliptic Curve Private Key Structure func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) { var err error @@ -39,7 +39,7 @@ func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) { return pkey, nil } -// Parse PEM encoded PKCS1 or PKCS8 public key +// ParseECPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) { var err error diff --git a/vendor/github.com/golang-jwt/jwt/ed25519.go b/vendor/github.com/golang-jwt/jwt/v5/ed25519.go similarity index 52% rename from vendor/github.com/golang-jwt/jwt/ed25519.go rename to vendor/github.com/golang-jwt/jwt/v5/ed25519.go index a2f8ddbe9..c2138119e 100644 --- a/vendor/github.com/golang-jwt/jwt/ed25519.go +++ b/vendor/github.com/golang-jwt/jwt/v5/ed25519.go @@ -1,16 +1,17 @@ package jwt import ( - "errors" - + "crypto" "crypto/ed25519" + "crypto/rand" + "errors" ) var ( ErrEd25519Verification = errors.New("ed25519: verification error") ) -// Implements the EdDSA family +// SigningMethodEd25519 implements the EdDSA family. // Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification type SigningMethodEd25519 struct{} @@ -30,27 +31,20 @@ func (m *SigningMethodEd25519) Alg() string { return "EdDSA" } -// Implements the Verify method from SigningMethod +// Verify implements token verification for the SigningMethod. // For this verify method, key must be an ed25519.PublicKey -func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error { - var err error +func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key interface{}) error { var ed25519Key ed25519.PublicKey var ok bool if ed25519Key, ok = key.(ed25519.PublicKey); !ok { - return ErrInvalidKeyType + return newError("Ed25519 verify expects ed25519.PublicKey", ErrInvalidKeyType) } if len(ed25519Key) != ed25519.PublicKeySize { return ErrInvalidKey } - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - // Verify the signature if !ed25519.Verify(ed25519Key, []byte(signingString), sig) { return ErrEd25519Verification @@ -59,23 +53,27 @@ func (m *SigningMethodEd25519) Verify(signingString, signature string, key inter return nil } -// Implements the Sign method from SigningMethod +// Sign implements token signing for the SigningMethod. // For this signing method, key must be an ed25519.PrivateKey -func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) { - var ed25519Key ed25519.PrivateKey +func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) ([]byte, error) { + var ed25519Key crypto.Signer var ok bool - if ed25519Key, ok = key.(ed25519.PrivateKey); !ok { - return "", ErrInvalidKeyType + if ed25519Key, ok = key.(crypto.Signer); !ok { + return nil, newError("Ed25519 sign expects crypto.Signer", ErrInvalidKeyType) + } + + if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok { + return nil, ErrInvalidKey } - // ed25519.Sign panics if private key not equal to ed25519.PrivateKeySize - // this allows to avoid recover usage - if len(ed25519Key) != ed25519.PrivateKeySize { - return "", ErrInvalidKey + // Sign the string and return the result. ed25519 performs a two-pass hash + // as part of its algorithm. Therefore, we need to pass a non-prehashed + // message into the Sign function, as indicated by crypto.Hash(0) + sig, err := ed25519Key.Sign(rand.Reader, []byte(signingString), crypto.Hash(0)) + if err != nil { + return nil, err } - // Sign the string and return the encoded result - sig := ed25519.Sign(ed25519Key, []byte(signingString)) - return EncodeSegment(sig), nil + return sig, nil } diff --git a/vendor/github.com/golang-jwt/jwt/ed25519_utils.go b/vendor/github.com/golang-jwt/jwt/v5/ed25519_utils.go similarity index 80% rename from vendor/github.com/golang-jwt/jwt/ed25519_utils.go rename to vendor/github.com/golang-jwt/jwt/v5/ed25519_utils.go index c6357275e..cdb5e68e8 100644 --- a/vendor/github.com/golang-jwt/jwt/ed25519_utils.go +++ b/vendor/github.com/golang-jwt/jwt/v5/ed25519_utils.go @@ -9,11 +9,11 @@ import ( ) var ( - ErrNotEdPrivateKey = errors.New("Key is not a valid Ed25519 private key") - ErrNotEdPublicKey = errors.New("Key is not a valid Ed25519 public key") + ErrNotEdPrivateKey = errors.New("key is not a valid Ed25519 private key") + ErrNotEdPublicKey = errors.New("key is not a valid Ed25519 public key") ) -// Parse PEM-encoded Edwards curve private key +// ParseEdPrivateKeyFromPEM parses a PEM-encoded Edwards curve private key func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) { var err error @@ -38,7 +38,7 @@ func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) { return pkey, nil } -// Parse PEM-encoded Edwards curve public key +// ParseEdPublicKeyFromPEM parses a PEM-encoded Edwards curve public key func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) { var err error diff --git a/vendor/github.com/golang-jwt/jwt/v5/errors.go b/vendor/github.com/golang-jwt/jwt/v5/errors.go new file mode 100644 index 000000000..23bb616dd --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/errors.go @@ -0,0 +1,49 @@ +package jwt + +import ( + "errors" + "strings" +) + +var ( + ErrInvalidKey = errors.New("key is invalid") + ErrInvalidKeyType = errors.New("key is of invalid type") + ErrHashUnavailable = errors.New("the requested hash function is unavailable") + ErrTokenMalformed = errors.New("token is malformed") + ErrTokenUnverifiable = errors.New("token is unverifiable") + ErrTokenSignatureInvalid = errors.New("token signature is invalid") + ErrTokenRequiredClaimMissing = errors.New("token is missing required claim") + ErrTokenInvalidAudience = errors.New("token has invalid audience") + ErrTokenExpired = errors.New("token is expired") + ErrTokenUsedBeforeIssued = errors.New("token used before issued") + ErrTokenInvalidIssuer = errors.New("token has invalid issuer") + ErrTokenInvalidSubject = errors.New("token has invalid subject") + ErrTokenNotValidYet = errors.New("token is not valid yet") + ErrTokenInvalidId = errors.New("token has invalid id") + ErrTokenInvalidClaims = errors.New("token has invalid claims") + ErrInvalidType = errors.New("invalid type for claim") +) + +// joinedError is an error type that works similar to what [errors.Join] +// produces, with the exception that it has a nice error string; mainly its +// error messages are concatenated using a comma, rather than a newline. +type joinedError struct { + errs []error +} + +func (je joinedError) Error() string { + msg := []string{} + for _, err := range je.errs { + msg = append(msg, err.Error()) + } + + return strings.Join(msg, ", ") +} + +// joinErrors joins together multiple errors. Useful for scenarios where +// multiple errors next to each other occur, e.g., in claims validation. +func joinErrors(errs ...error) error { + return &joinedError{ + errs: errs, + } +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/errors_go1_20.go b/vendor/github.com/golang-jwt/jwt/v5/errors_go1_20.go new file mode 100644 index 000000000..a893d355e --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/errors_go1_20.go @@ -0,0 +1,47 @@ +//go:build go1.20 +// +build go1.20 + +package jwt + +import ( + "fmt" +) + +// Unwrap implements the multiple error unwrapping for this error type, which is +// possible in Go 1.20. +func (je joinedError) Unwrap() []error { + return je.errs +} + +// newError creates a new error message with a detailed error message. The +// message will be prefixed with the contents of the supplied error type. +// Additionally, more errors, that provide more context can be supplied which +// will be appended to the message. This makes use of Go 1.20's possibility to +// include more than one %w formatting directive in [fmt.Errorf]. +// +// For example, +// +// newError("no keyfunc was provided", ErrTokenUnverifiable) +// +// will produce the error string +// +// "token is unverifiable: no keyfunc was provided" +func newError(message string, err error, more ...error) error { + var format string + var args []any + if message != "" { + format = "%w: %s" + args = []any{err, message} + } else { + format = "%w" + args = []any{err} + } + + for _, e := range more { + format += ": %w" + args = append(args, e) + } + + err = fmt.Errorf(format, args...) + return err +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go b/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go new file mode 100644 index 000000000..2ad542f00 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go @@ -0,0 +1,78 @@ +//go:build !go1.20 +// +build !go1.20 + +package jwt + +import ( + "errors" + "fmt" +) + +// Is implements checking for multiple errors using [errors.Is], since multiple +// error unwrapping is not possible in versions less than Go 1.20. +func (je joinedError) Is(err error) bool { + for _, e := range je.errs { + if errors.Is(e, err) { + return true + } + } + + return false +} + +// wrappedErrors is a workaround for wrapping multiple errors in environments +// where Go 1.20 is not available. It basically uses the already implemented +// functionality of joinedError to handle multiple errors with supplies a +// custom error message that is identical to the one we produce in Go 1.20 using +// multiple %w directives. +type wrappedErrors struct { + msg string + joinedError +} + +// Error returns the stored error string +func (we wrappedErrors) Error() string { + return we.msg +} + +// newError creates a new error message with a detailed error message. The +// message will be prefixed with the contents of the supplied error type. +// Additionally, more errors, that provide more context can be supplied which +// will be appended to the message. Since we cannot use of Go 1.20's possibility +// to include more than one %w formatting directive in [fmt.Errorf], we have to +// emulate that. +// +// For example, +// +// newError("no keyfunc was provided", ErrTokenUnverifiable) +// +// will produce the error string +// +// "token is unverifiable: no keyfunc was provided" +func newError(message string, err error, more ...error) error { + // We cannot wrap multiple errors here with %w, so we have to be a little + // bit creative. Basically, we are using %s instead of %w to produce the + // same error message and then throw the result into a custom error struct. + var format string + var args []any + if message != "" { + format = "%s: %s" + args = []any{err, message} + } else { + format = "%s" + args = []any{err} + } + errs := []error{err} + + for _, e := range more { + format += ": %s" + args = append(args, e) + errs = append(errs, e) + } + + err = &wrappedErrors{ + msg: fmt.Sprintf(format, args...), + joinedError: joinedError{errs: errs}, + } + return err +} diff --git a/vendor/github.com/golang-jwt/jwt/hmac.go b/vendor/github.com/golang-jwt/jwt/v5/hmac.go similarity index 53% rename from vendor/github.com/golang-jwt/jwt/hmac.go rename to vendor/github.com/golang-jwt/jwt/v5/hmac.go index addbe5d40..aca600ce1 100644 --- a/vendor/github.com/golang-jwt/jwt/hmac.go +++ b/vendor/github.com/golang-jwt/jwt/v5/hmac.go @@ -6,7 +6,7 @@ import ( "errors" ) -// Implements the HMAC-SHA family of signing methods signing methods +// SigningMethodHMAC implements the HMAC-SHA family of signing methods. // Expects key type of []byte for both signing and validation type SigningMethodHMAC struct { Name string @@ -45,18 +45,21 @@ func (m *SigningMethodHMAC) Alg() string { return m.Name } -// Verify the signature of HSXXX tokens. Returns nil if the signature is valid. -func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error { +// Verify implements token verification for the SigningMethod. Returns nil if +// the signature is valid. Key must be []byte. +// +// Note it is not advised to provide a []byte which was converted from a 'human +// readable' string using a subset of ASCII characters. To maximize entropy, you +// should ideally be providing a []byte key which was produced from a +// cryptographically random source, e.g. crypto/rand. Additional information +// about this, and why we intentionally are not supporting string as a key can +// be found on our usage guide +// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types. +func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interface{}) error { // Verify the key is the right type keyBytes, ok := key.([]byte) if !ok { - return ErrInvalidKeyType - } - - // Decode signature, for comparison - sig, err := DecodeSegment(signature) - if err != nil { - return err + return newError("HMAC verify expects []byte", ErrInvalidKeyType) } // Can we use the specified hashing method? @@ -77,19 +80,25 @@ func (m *SigningMethodHMAC) Verify(signingString, signature string, key interfac return nil } -// Implements the Sign method from SigningMethod for this signing method. -// Key must be []byte -func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) { +// Sign implements token signing for the SigningMethod. Key must be []byte. +// +// Note it is not advised to provide a []byte which was converted from a 'human +// readable' string using a subset of ASCII characters. To maximize entropy, you +// should ideally be providing a []byte key which was produced from a +// cryptographically random source, e.g. crypto/rand. Additional information +// about this, and why we intentionally are not supporting string as a key can +// be found on our usage guide https://golang-jwt.github.io/jwt/usage/signing_methods/. +func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) { if keyBytes, ok := key.([]byte); ok { if !m.Hash.Available() { - return "", ErrHashUnavailable + return nil, ErrHashUnavailable } hasher := hmac.New(m.Hash.New, keyBytes) hasher.Write([]byte(signingString)) - return EncodeSegment(hasher.Sum(nil)), nil + return hasher.Sum(nil), nil } - return "", ErrInvalidKeyType + return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType) } diff --git a/vendor/github.com/golang-jwt/jwt/v5/map_claims.go b/vendor/github.com/golang-jwt/jwt/v5/map_claims.go new file mode 100644 index 000000000..b2b51a1f8 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/map_claims.go @@ -0,0 +1,109 @@ +package jwt + +import ( + "encoding/json" + "fmt" +) + +// MapClaims is a claims type that uses the map[string]interface{} for JSON +// decoding. This is the default claims type if you don't supply one +type MapClaims map[string]interface{} + +// GetExpirationTime implements the Claims interface. +func (m MapClaims) GetExpirationTime() (*NumericDate, error) { + return m.parseNumericDate("exp") +} + +// GetNotBefore implements the Claims interface. +func (m MapClaims) GetNotBefore() (*NumericDate, error) { + return m.parseNumericDate("nbf") +} + +// GetIssuedAt implements the Claims interface. +func (m MapClaims) GetIssuedAt() (*NumericDate, error) { + return m.parseNumericDate("iat") +} + +// GetAudience implements the Claims interface. +func (m MapClaims) GetAudience() (ClaimStrings, error) { + return m.parseClaimsString("aud") +} + +// GetIssuer implements the Claims interface. +func (m MapClaims) GetIssuer() (string, error) { + return m.parseString("iss") +} + +// GetSubject implements the Claims interface. +func (m MapClaims) GetSubject() (string, error) { + return m.parseString("sub") +} + +// parseNumericDate tries to parse a key in the map claims type as a number +// date. This will succeed, if the underlying type is either a [float64] or a +// [json.Number]. Otherwise, nil will be returned. +func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) { + v, ok := m[key] + if !ok { + return nil, nil + } + + switch exp := v.(type) { + case float64: + if exp == 0 { + return nil, nil + } + + return newNumericDateFromSeconds(exp), nil + case json.Number: + v, _ := exp.Float64() + + return newNumericDateFromSeconds(v), nil + } + + return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType) +} + +// parseClaimsString tries to parse a key in the map claims type as a +// [ClaimsStrings] type, which can either be a string or an array of string. +func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) { + var cs []string + switch v := m[key].(type) { + case string: + cs = append(cs, v) + case []string: + cs = v + case []interface{}: + for _, a := range v { + vs, ok := a.(string) + if !ok { + return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType) + } + cs = append(cs, vs) + } + } + + return cs, nil +} + +// parseString tries to parse a key in the map claims type as a [string] type. +// If the key does not exist, an empty string is returned. If the key has the +// wrong type, an error is returned. +func (m MapClaims) parseString(key string) (string, error) { + var ( + ok bool + raw interface{} + iss string + ) + raw, ok = m[key] + if !ok { + return "", nil + } + + iss, ok = raw.(string) + if !ok { + return "", newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType) + } + + return iss, nil +} diff --git a/vendor/github.com/golang-jwt/jwt/none.go b/vendor/github.com/golang-jwt/jwt/v5/none.go similarity index 68% rename from vendor/github.com/golang-jwt/jwt/none.go rename to vendor/github.com/golang-jwt/jwt/v5/none.go index f04d189d0..685c2ea30 100644 --- a/vendor/github.com/golang-jwt/jwt/none.go +++ b/vendor/github.com/golang-jwt/jwt/v5/none.go @@ -1,6 +1,6 @@ package jwt -// Implements the none signing method. This is required by the spec +// SigningMethodNone implements the none signing method. This is required by the spec // but you probably should never use it. var SigningMethodNone *signingMethodNone @@ -13,7 +13,7 @@ type unsafeNoneMagicConstant string func init() { SigningMethodNone = &signingMethodNone{} - NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid) + NoneSignatureTypeDisallowedError = newError("'none' signature type is not allowed", ErrTokenUnverifiable) RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod { return SigningMethodNone @@ -25,18 +25,15 @@ func (m *signingMethodNone) Alg() string { } // Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key -func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) { +func (m *signingMethodNone) Verify(signingString string, sig []byte, key interface{}) (err error) { // Key must be UnsafeAllowNoneSignatureType to prevent accidentally // accepting 'none' signing method if _, ok := key.(unsafeNoneMagicConstant); !ok { return NoneSignatureTypeDisallowedError } // If signing method is none, signature must be an empty string - if signature != "" { - return NewValidationError( - "'none' signing method with non-empty signature", - ValidationErrorSignatureInvalid, - ) + if len(sig) != 0 { + return newError("'none' signing method with non-empty signature", ErrTokenUnverifiable) } // Accept 'none' signing method. @@ -44,9 +41,10 @@ func (m *signingMethodNone) Verify(signingString, signature string, key interfac } // Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key -func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) { +func (m *signingMethodNone) Sign(signingString string, key interface{}) ([]byte, error) { if _, ok := key.(unsafeNoneMagicConstant); ok { - return "", nil + return []byte{}, nil } - return "", NoneSignatureTypeDisallowedError + + return nil, NoneSignatureTypeDisallowedError } diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser.go b/vendor/github.com/golang-jwt/jwt/v5/parser.go new file mode 100644 index 000000000..ecf99af78 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/parser.go @@ -0,0 +1,238 @@ +package jwt + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "strings" +) + +type Parser struct { + // If populated, only these methods will be considered valid. + validMethods []string + + // Use JSON Number format in JSON decoder. + useJSONNumber bool + + // Skip claims validation during token parsing. + skipClaimsValidation bool + + validator *Validator + + decodeStrict bool + + decodePaddingAllowed bool +} + +// NewParser creates a new Parser with the specified options +func NewParser(options ...ParserOption) *Parser { + p := &Parser{ + validator: &Validator{}, + } + + // Loop through our parsing options and apply them + for _, option := range options { + option(p) + } + + return p +} + +// Parse parses, validates, verifies the signature and returns the parsed token. +// keyFunc will receive the parsed token and should return the key for validating. +func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { + return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc) +} + +// ParseWithClaims parses, validates, and verifies like Parse, but supplies a default object implementing the Claims +// interface. This provides default values which can be overridden and allows a caller to use their own type, rather +// than the default MapClaims implementation of Claims. +// +// Note: If you provide a custom claim implementation that embeds one of the standard claims (such as RegisteredClaims), +// make sure that a) you either embed a non-pointer version of the claims or b) if you are using a pointer, allocate the +// proper memory for it before passing in the overall claims, otherwise you might run into a panic. +func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { + token, parts, err := p.ParseUnverified(tokenString, claims) + if err != nil { + return token, err + } + + // Verify signing method is in the required set + if p.validMethods != nil { + var signingMethodValid = false + var alg = token.Method.Alg() + for _, m := range p.validMethods { + if m == alg { + signingMethodValid = true + break + } + } + if !signingMethodValid { + // signing method is not in the listed set + return token, newError(fmt.Sprintf("signing method %v is invalid", alg), ErrTokenSignatureInvalid) + } + } + + // Decode signature + token.Signature, err = p.DecodeSegment(parts[2]) + if err != nil { + return token, newError("could not base64 decode signature", ErrTokenMalformed, err) + } + text := strings.Join(parts[0:2], ".") + + // Lookup key(s) + if keyFunc == nil { + // keyFunc was not provided. short circuiting validation + return token, newError("no keyfunc was provided", ErrTokenUnverifiable) + } + + got, err := keyFunc(token) + if err != nil { + return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err) + } + + switch have := got.(type) { + case VerificationKeySet: + if len(have.Keys) == 0 { + return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable) + } + // Iterate through keys and verify signature, skipping the rest when a match is found. + // Return the last error if no match is found. + for _, key := range have.Keys { + if err = token.Method.Verify(text, token.Signature, key); err == nil { + break + } + } + default: + err = token.Method.Verify(text, token.Signature, have) + } + if err != nil { + return token, newError("", ErrTokenSignatureInvalid, err) + } + + // Validate Claims + if !p.skipClaimsValidation { + // Make sure we have at least a default validator + if p.validator == nil { + p.validator = NewValidator() + } + + if err := p.validator.Validate(claims); err != nil { + return token, newError("", ErrTokenInvalidClaims, err) + } + } + + // No errors so far, token is valid. + token.Valid = true + + return token, nil +} + +// ParseUnverified parses the token but doesn't validate the signature. +// +// WARNING: Don't use this method unless you know what you're doing. +// +// It's only ever useful in cases where you know the signature is valid (since it has already +// been or will be checked elsewhere in the stack) and you want to extract values from it. +func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) { + parts = strings.Split(tokenString, ".") + if len(parts) != 3 { + return nil, parts, newError("token contains an invalid number of segments", ErrTokenMalformed) + } + + token = &Token{Raw: tokenString} + + // parse Header + var headerBytes []byte + if headerBytes, err = p.DecodeSegment(parts[0]); err != nil { + return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err) + } + if err = json.Unmarshal(headerBytes, &token.Header); err != nil { + return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err) + } + + // parse Claims + token.Claims = claims + + claimBytes, err := p.DecodeSegment(parts[1]) + if err != nil { + return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err) + } + + // If `useJSONNumber` is enabled then we must use *json.Decoder to decode + // the claims. However, this comes with a performance penalty so only use + // it if we must and, otherwise, simple use json.Unmarshal. + if !p.useJSONNumber { + // JSON Unmarshal. Special case for map type to avoid weird pointer behavior. + if c, ok := token.Claims.(MapClaims); ok { + err = json.Unmarshal(claimBytes, &c) + } else { + err = json.Unmarshal(claimBytes, &claims) + } + } else { + dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) + dec.UseNumber() + // JSON Decode. Special case for map type to avoid weird pointer behavior. + if c, ok := token.Claims.(MapClaims); ok { + err = dec.Decode(&c) + } else { + err = dec.Decode(&claims) + } + } + if err != nil { + return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err) + } + + // Lookup signature method + if method, ok := token.Header["alg"].(string); ok { + if token.Method = GetSigningMethod(method); token.Method == nil { + return token, parts, newError("signing method (alg) is unavailable", ErrTokenUnverifiable) + } + } else { + return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable) + } + + return token, parts, nil +} + +// DecodeSegment decodes a JWT specific base64url encoding. This function will +// take into account whether the [Parser] is configured with additional options, +// such as [WithStrictDecoding] or [WithPaddingAllowed]. +func (p *Parser) DecodeSegment(seg string) ([]byte, error) { + encoding := base64.RawURLEncoding + + if p.decodePaddingAllowed { + if l := len(seg) % 4; l > 0 { + seg += strings.Repeat("=", 4-l) + } + encoding = base64.URLEncoding + } + + if p.decodeStrict { + encoding = encoding.Strict() + } + return encoding.DecodeString(seg) +} + +// Parse parses, validates, verifies the signature and returns the parsed token. +// keyFunc will receive the parsed token and should return the cryptographic key +// for verifying the signature. The caller is strongly encouraged to set the +// WithValidMethods option to validate the 'alg' claim in the token matches the +// expected algorithm. For more details about the importance of validating the +// 'alg' claim, see +// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/ +func Parse(tokenString string, keyFunc Keyfunc, options ...ParserOption) (*Token, error) { + return NewParser(options...).Parse(tokenString, keyFunc) +} + +// ParseWithClaims is a shortcut for NewParser().ParseWithClaims(). +// +// Note: If you provide a custom claim implementation that embeds one of the +// standard claims (such as RegisteredClaims), make sure that a) you either +// embed a non-pointer version of the claims or b) if you are using a pointer, +// allocate the proper memory for it before passing in the overall claims, +// otherwise you might run into a panic. +func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) { + return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc) +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser_option.go b/vendor/github.com/golang-jwt/jwt/v5/parser_option.go new file mode 100644 index 000000000..88a780fbd --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/parser_option.go @@ -0,0 +1,128 @@ +package jwt + +import "time" + +// ParserOption is used to implement functional-style options that modify the +// behavior of the parser. To add new options, just create a function (ideally +// beginning with With or Without) that returns an anonymous function that takes +// a *Parser type as input and manipulates its configuration accordingly. +type ParserOption func(*Parser) + +// WithValidMethods is an option to supply algorithm methods that the parser +// will check. Only those methods will be considered valid. It is heavily +// encouraged to use this option in order to prevent attacks such as +// https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/. +func WithValidMethods(methods []string) ParserOption { + return func(p *Parser) { + p.validMethods = methods + } +} + +// WithJSONNumber is an option to configure the underlying JSON parser with +// UseNumber. +func WithJSONNumber() ParserOption { + return func(p *Parser) { + p.useJSONNumber = true + } +} + +// WithoutClaimsValidation is an option to disable claims validation. This +// option should only be used if you exactly know what you are doing. +func WithoutClaimsValidation() ParserOption { + return func(p *Parser) { + p.skipClaimsValidation = true + } +} + +// WithLeeway returns the ParserOption for specifying the leeway window. +func WithLeeway(leeway time.Duration) ParserOption { + return func(p *Parser) { + p.validator.leeway = leeway + } +} + +// WithTimeFunc returns the ParserOption for specifying the time func. The +// primary use-case for this is testing. If you are looking for a way to account +// for clock-skew, WithLeeway should be used instead. +func WithTimeFunc(f func() time.Time) ParserOption { + return func(p *Parser) { + p.validator.timeFunc = f + } +} + +// WithIssuedAt returns the ParserOption to enable verification +// of issued-at. +func WithIssuedAt() ParserOption { + return func(p *Parser) { + p.validator.verifyIat = true + } +} + +// WithExpirationRequired returns the ParserOption to make exp claim required. +// By default exp claim is optional. +func WithExpirationRequired() ParserOption { + return func(p *Parser) { + p.validator.requireExp = true + } +} + +// WithAudience configures the validator to require the specified audience in +// the `aud` claim. Validation will fail if the audience is not listed in the +// token or the `aud` claim is missing. +// +// NOTE: While the `aud` claim is OPTIONAL in a JWT, the handling of it is +// application-specific. Since this validation API is helping developers in +// writing secure application, we decided to REQUIRE the existence of the claim, +// if an audience is expected. +func WithAudience(aud string) ParserOption { + return func(p *Parser) { + p.validator.expectedAud = aud + } +} + +// WithIssuer configures the validator to require the specified issuer in the +// `iss` claim. Validation will fail if a different issuer is specified in the +// token or the `iss` claim is missing. +// +// NOTE: While the `iss` claim is OPTIONAL in a JWT, the handling of it is +// application-specific. Since this validation API is helping developers in +// writing secure application, we decided to REQUIRE the existence of the claim, +// if an issuer is expected. +func WithIssuer(iss string) ParserOption { + return func(p *Parser) { + p.validator.expectedIss = iss + } +} + +// WithSubject configures the validator to require the specified subject in the +// `sub` claim. Validation will fail if a different subject is specified in the +// token or the `sub` claim is missing. +// +// NOTE: While the `sub` claim is OPTIONAL in a JWT, the handling of it is +// application-specific. Since this validation API is helping developers in +// writing secure application, we decided to REQUIRE the existence of the claim, +// if a subject is expected. +func WithSubject(sub string) ParserOption { + return func(p *Parser) { + p.validator.expectedSub = sub + } +} + +// WithPaddingAllowed will enable the codec used for decoding JWTs to allow +// padding. Note that the JWS RFC7515 states that the tokens will utilize a +// Base64url encoding with no padding. Unfortunately, some implementations of +// JWT are producing non-standard tokens, and thus require support for decoding. +func WithPaddingAllowed() ParserOption { + return func(p *Parser) { + p.decodePaddingAllowed = true + } +} + +// WithStrictDecoding will switch the codec used for decoding JWTs into strict +// mode. In this mode, the decoder requires that trailing padding bits are zero, +// as described in RFC 4648 section 3.5. +func WithStrictDecoding() ParserOption { + return func(p *Parser) { + p.decodeStrict = true + } +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/registered_claims.go b/vendor/github.com/golang-jwt/jwt/v5/registered_claims.go new file mode 100644 index 000000000..77951a531 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/registered_claims.go @@ -0,0 +1,63 @@ +package jwt + +// RegisteredClaims are a structured version of the JWT Claims Set, +// restricted to Registered Claim Names, as referenced at +// https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 +// +// This type can be used on its own, but then additional private and +// public claims embedded in the JWT will not be parsed. The typical use-case +// therefore is to embedded this in a user-defined claim type. +// +// See examples for how to use this with your own claim types. +type RegisteredClaims struct { + // the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1 + Issuer string `json:"iss,omitempty"` + + // the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2 + Subject string `json:"sub,omitempty"` + + // the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3 + Audience ClaimStrings `json:"aud,omitempty"` + + // the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4 + ExpiresAt *NumericDate `json:"exp,omitempty"` + + // the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5 + NotBefore *NumericDate `json:"nbf,omitempty"` + + // the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6 + IssuedAt *NumericDate `json:"iat,omitempty"` + + // the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7 + ID string `json:"jti,omitempty"` +} + +// GetExpirationTime implements the Claims interface. +func (c RegisteredClaims) GetExpirationTime() (*NumericDate, error) { + return c.ExpiresAt, nil +} + +// GetNotBefore implements the Claims interface. +func (c RegisteredClaims) GetNotBefore() (*NumericDate, error) { + return c.NotBefore, nil +} + +// GetIssuedAt implements the Claims interface. +func (c RegisteredClaims) GetIssuedAt() (*NumericDate, error) { + return c.IssuedAt, nil +} + +// GetAudience implements the Claims interface. +func (c RegisteredClaims) GetAudience() (ClaimStrings, error) { + return c.Audience, nil +} + +// GetIssuer implements the Claims interface. +func (c RegisteredClaims) GetIssuer() (string, error) { + return c.Issuer, nil +} + +// GetSubject implements the Claims interface. +func (c RegisteredClaims) GetSubject() (string, error) { + return c.Subject, nil +} diff --git a/vendor/github.com/golang-jwt/jwt/rsa.go b/vendor/github.com/golang-jwt/jwt/v5/rsa.go similarity index 77% rename from vendor/github.com/golang-jwt/jwt/rsa.go rename to vendor/github.com/golang-jwt/jwt/v5/rsa.go index e4caf1ca4..83cbee6ae 100644 --- a/vendor/github.com/golang-jwt/jwt/rsa.go +++ b/vendor/github.com/golang-jwt/jwt/v5/rsa.go @@ -6,7 +6,7 @@ import ( "crypto/rsa" ) -// Implements the RSA family of signing methods signing methods +// SigningMethodRSA implements the RSA family of signing methods. // Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation type SigningMethodRSA struct { Name string @@ -44,22 +44,14 @@ func (m *SigningMethodRSA) Alg() string { return m.Name } -// Implements the Verify method from SigningMethod +// Verify implements token verification for the SigningMethod // For this signing method, must be an *rsa.PublicKey structure. -func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error { - var err error - - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - +func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interface{}) error { var rsaKey *rsa.PublicKey var ok bool if rsaKey, ok = key.(*rsa.PublicKey); !ok { - return ErrInvalidKeyType + return newError("RSA verify expects *rsa.PublicKey", ErrInvalidKeyType) } // Create hasher @@ -73,20 +65,20 @@ func (m *SigningMethodRSA) Verify(signingString, signature string, key interface return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig) } -// Implements the Sign method from SigningMethod +// Sign implements token signing for the SigningMethod // For this signing method, must be an *rsa.PrivateKey structure. -func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) { +func (m *SigningMethodRSA) Sign(signingString string, key interface{}) ([]byte, error) { var rsaKey *rsa.PrivateKey var ok bool // Validate type of key if rsaKey, ok = key.(*rsa.PrivateKey); !ok { - return "", ErrInvalidKey + return nil, newError("RSA sign expects *rsa.PrivateKey", ErrInvalidKeyType) } // Create the hasher if !m.Hash.Available() { - return "", ErrHashUnavailable + return nil, ErrHashUnavailable } hasher := m.Hash.New() @@ -94,8 +86,8 @@ func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, // Sign the string and return the encoded bytes if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil { - return EncodeSegment(sigBytes), nil + return sigBytes, nil } else { - return "", err + return nil, err } } diff --git a/vendor/github.com/golang-jwt/jwt/rsa_pss.go b/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go similarity index 83% rename from vendor/github.com/golang-jwt/jwt/rsa_pss.go rename to vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go index c01470864..28c386ec4 100644 --- a/vendor/github.com/golang-jwt/jwt/rsa_pss.go +++ b/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go @@ -1,3 +1,4 @@ +//go:build go1.4 // +build go1.4 package jwt @@ -8,7 +9,7 @@ import ( "crypto/rsa" ) -// Implements the RSAPSS family of signing methods signing methods +// SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods type SigningMethodRSAPSS struct { *SigningMethodRSA Options *rsa.PSSOptions @@ -79,23 +80,15 @@ func init() { }) } -// Implements the Verify method from SigningMethod +// Verify implements token verification for the SigningMethod. // For this verify method, key must be an rsa.PublicKey struct -func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error { - var err error - - // Decode the signature - var sig []byte - if sig, err = DecodeSegment(signature); err != nil { - return err - } - +func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key interface{}) error { var rsaKey *rsa.PublicKey switch k := key.(type) { case *rsa.PublicKey: rsaKey = k default: - return ErrInvalidKey + return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType) } // Create hasher @@ -113,21 +106,21 @@ func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interf return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts) } -// Implements the Sign method from SigningMethod +// Sign implements token signing for the SigningMethod. // For this signing method, key must be an rsa.PrivateKey struct -func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) { +func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byte, error) { var rsaKey *rsa.PrivateKey switch k := key.(type) { case *rsa.PrivateKey: rsaKey = k default: - return "", ErrInvalidKeyType + return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType) } // Create the hasher if !m.Hash.Available() { - return "", ErrHashUnavailable + return nil, ErrHashUnavailable } hasher := m.Hash.New() @@ -135,8 +128,8 @@ func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (strin // Sign the string and return the encoded bytes if sigBytes, err := rsa.SignPSS(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil), m.Options); err == nil { - return EncodeSegment(sigBytes), nil + return sigBytes, nil } else { - return "", err + return nil, err } } diff --git a/vendor/github.com/golang-jwt/jwt/rsa_utils.go b/vendor/github.com/golang-jwt/jwt/v5/rsa_utils.go similarity index 69% rename from vendor/github.com/golang-jwt/jwt/rsa_utils.go rename to vendor/github.com/golang-jwt/jwt/v5/rsa_utils.go index 14c78c292..b3aeebbe1 100644 --- a/vendor/github.com/golang-jwt/jwt/rsa_utils.go +++ b/vendor/github.com/golang-jwt/jwt/v5/rsa_utils.go @@ -8,12 +8,12 @@ import ( ) var ( - ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be a PEM encoded PKCS1 or PKCS8 key") - ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key") - ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public key") + ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key") + ErrNotRSAPrivateKey = errors.New("key is not a valid RSA private key") + ErrNotRSAPublicKey = errors.New("key is not a valid RSA public key") ) -// Parse PEM encoded PKCS1 or PKCS8 private key +// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { var err error @@ -39,7 +39,11 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { return pkey, nil } -// Parse PEM encoded PKCS1 or PKCS8 private key protected with password +// ParseRSAPrivateKeyFromPEMWithPassword parses a PEM encoded PKCS1 or PKCS8 private key protected with password +// +// Deprecated: This function is deprecated and should not be used anymore. It uses the deprecated x509.DecryptPEMBlock +// function, which was deprecated since RFC 1423 is regarded insecure by design. Unfortunately, there is no alternative +// in the Go standard library for now. See https://github.com/golang/go/issues/8860. func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) { var err error @@ -71,7 +75,7 @@ func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.Pr return pkey, nil } -// Parse PEM encoded PKCS1 or PKCS8 public key +// ParseRSAPublicKeyFromPEM parses a certificate or a PEM encoded PKCS1 or PKIX public key func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { var err error @@ -87,7 +91,9 @@ func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { if cert, err := x509.ParseCertificate(block.Bytes); err == nil { parsedKey = cert.PublicKey } else { - return nil, err + if parsedKey, err = x509.ParsePKCS1PublicKey(block.Bytes); err != nil { + return nil, err + } } } diff --git a/vendor/github.com/golang-jwt/jwt/v5/signing_method.go b/vendor/github.com/golang-jwt/jwt/v5/signing_method.go new file mode 100644 index 000000000..0d73631c1 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/signing_method.go @@ -0,0 +1,49 @@ +package jwt + +import ( + "sync" +) + +var signingMethods = map[string]func() SigningMethod{} +var signingMethodLock = new(sync.RWMutex) + +// SigningMethod can be used add new methods for signing or verifying tokens. It +// takes a decoded signature as an input in the Verify function and produces a +// signature in Sign. The signature is then usually base64 encoded as part of a +// JWT. +type SigningMethod interface { + Verify(signingString string, sig []byte, key interface{}) error // Returns nil if signature is valid + Sign(signingString string, key interface{}) ([]byte, error) // Returns signature or error + Alg() string // returns the alg identifier for this method (example: 'HS256') +} + +// RegisterSigningMethod registers the "alg" name and a factory function for signing method. +// This is typically done during init() in the method's implementation +func RegisterSigningMethod(alg string, f func() SigningMethod) { + signingMethodLock.Lock() + defer signingMethodLock.Unlock() + + signingMethods[alg] = f +} + +// GetSigningMethod retrieves a signing method from an "alg" string +func GetSigningMethod(alg string) (method SigningMethod) { + signingMethodLock.RLock() + defer signingMethodLock.RUnlock() + + if methodF, ok := signingMethods[alg]; ok { + method = methodF() + } + return +} + +// GetAlgorithms returns a list of registered "alg" names +func GetAlgorithms() (algs []string) { + signingMethodLock.RLock() + defer signingMethodLock.RUnlock() + + for alg := range signingMethods { + algs = append(algs, alg) + } + return +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf b/vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf new file mode 100644 index 000000000..53745d51d --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/staticcheck.conf @@ -0,0 +1 @@ +checks = ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1023"] diff --git a/vendor/github.com/golang-jwt/jwt/v5/token.go b/vendor/github.com/golang-jwt/jwt/v5/token.go new file mode 100644 index 000000000..352873a2d --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/token.go @@ -0,0 +1,100 @@ +package jwt + +import ( + "crypto" + "encoding/base64" + "encoding/json" +) + +// Keyfunc will be used by the Parse methods as a callback function to supply +// the key for verification. The function receives the parsed, but unverified +// Token. This allows you to use properties in the Header of the token (such as +// `kid`) to identify which key to use. +// +// The returned interface{} may be a single key or a VerificationKeySet containing +// multiple keys. +type Keyfunc func(*Token) (interface{}, error) + +// VerificationKey represents a public or secret key for verifying a token's signature. +type VerificationKey interface { + crypto.PublicKey | []uint8 +} + +// VerificationKeySet is a set of public or secret keys. It is used by the parser to verify a token. +type VerificationKeySet struct { + Keys []VerificationKey +} + +// Token represents a JWT Token. Different fields will be used depending on +// whether you're creating or parsing/verifying a token. +type Token struct { + Raw string // Raw contains the raw token. Populated when you [Parse] a token + Method SigningMethod // Method is the signing method used or to be used + Header map[string]interface{} // Header is the first segment of the token in decoded form + Claims Claims // Claims is the second segment of the token in decoded form + Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token + Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token +} + +// New creates a new [Token] with the specified signing method and an empty map +// of claims. Additional options can be specified, but are currently unused. +func New(method SigningMethod, opts ...TokenOption) *Token { + return NewWithClaims(method, MapClaims{}, opts...) +} + +// NewWithClaims creates a new [Token] with the specified signing method and +// claims. Additional options can be specified, but are currently unused. +func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token { + return &Token{ + Header: map[string]interface{}{ + "typ": "JWT", + "alg": method.Alg(), + }, + Claims: claims, + Method: method, + } +} + +// SignedString creates and returns a complete, signed JWT. The token is signed +// using the SigningMethod specified in the token. Please refer to +// https://golang-jwt.github.io/jwt/usage/signing_methods/#signing-methods-and-key-types +// for an overview of the different signing methods and their respective key +// types. +func (t *Token) SignedString(key interface{}) (string, error) { + sstr, err := t.SigningString() + if err != nil { + return "", err + } + + sig, err := t.Method.Sign(sstr, key) + if err != nil { + return "", err + } + + return sstr + "." + t.EncodeSegment(sig), nil +} + +// SigningString generates the signing string. This is the most expensive part +// of the whole deal. Unless you need this for something special, just go +// straight for the SignedString. +func (t *Token) SigningString() (string, error) { + h, err := json.Marshal(t.Header) + if err != nil { + return "", err + } + + c, err := json.Marshal(t.Claims) + if err != nil { + return "", err + } + + return t.EncodeSegment(h) + "." + t.EncodeSegment(c), nil +} + +// EncodeSegment encodes a JWT specific base64url encoding with padding +// stripped. In the future, this function might take into account a +// [TokenOption]. Therefore, this function exists as a method of [Token], rather +// than a global function. +func (*Token) EncodeSegment(seg []byte) string { + return base64.RawURLEncoding.EncodeToString(seg) +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/token_option.go b/vendor/github.com/golang-jwt/jwt/v5/token_option.go new file mode 100644 index 000000000..b4ae3badf --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/token_option.go @@ -0,0 +1,5 @@ +package jwt + +// TokenOption is a reserved type, which provides some forward compatibility, +// if we ever want to introduce token creation-related options. +type TokenOption func(*Token) diff --git a/vendor/github.com/golang-jwt/jwt/v5/types.go b/vendor/github.com/golang-jwt/jwt/v5/types.go new file mode 100644 index 000000000..b2655a9e6 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/types.go @@ -0,0 +1,149 @@ +package jwt + +import ( + "encoding/json" + "fmt" + "math" + "strconv" + "time" +) + +// TimePrecision sets the precision of times and dates within this library. This +// has an influence on the precision of times when comparing expiry or other +// related time fields. Furthermore, it is also the precision of times when +// serializing. +// +// For backwards compatibility the default precision is set to seconds, so that +// no fractional timestamps are generated. +var TimePrecision = time.Second + +// MarshalSingleStringAsArray modifies the behavior of the ClaimStrings type, +// especially its MarshalJSON function. +// +// If it is set to true (the default), it will always serialize the type as an +// array of strings, even if it just contains one element, defaulting to the +// behavior of the underlying []string. If it is set to false, it will serialize +// to a single string, if it contains one element. Otherwise, it will serialize +// to an array of strings. +var MarshalSingleStringAsArray = true + +// NumericDate represents a JSON numeric date value, as referenced at +// https://datatracker.ietf.org/doc/html/rfc7519#section-2. +type NumericDate struct { + time.Time +} + +// NewNumericDate constructs a new *NumericDate from a standard library time.Time struct. +// It will truncate the timestamp according to the precision specified in TimePrecision. +func NewNumericDate(t time.Time) *NumericDate { + return &NumericDate{t.Truncate(TimePrecision)} +} + +// newNumericDateFromSeconds creates a new *NumericDate out of a float64 representing a +// UNIX epoch with the float fraction representing non-integer seconds. +func newNumericDateFromSeconds(f float64) *NumericDate { + round, frac := math.Modf(f) + return NewNumericDate(time.Unix(int64(round), int64(frac*1e9))) +} + +// MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch +// represented in NumericDate to a byte array, using the precision specified in TimePrecision. +func (date NumericDate) MarshalJSON() (b []byte, err error) { + var prec int + if TimePrecision < time.Second { + prec = int(math.Log10(float64(time.Second) / float64(TimePrecision))) + } + truncatedDate := date.Truncate(TimePrecision) + + // For very large timestamps, UnixNano would overflow an int64, but this + // function requires nanosecond level precision, so we have to use the + // following technique to get round the issue: + // + // 1. Take the normal unix timestamp to form the whole number part of the + // output, + // 2. Take the result of the Nanosecond function, which returns the offset + // within the second of the particular unix time instance, to form the + // decimal part of the output + // 3. Concatenate them to produce the final result + seconds := strconv.FormatInt(truncatedDate.Unix(), 10) + nanosecondsOffset := strconv.FormatFloat(float64(truncatedDate.Nanosecond())/float64(time.Second), 'f', prec, 64) + + output := append([]byte(seconds), []byte(nanosecondsOffset)[1:]...) + + return output, nil +} + +// UnmarshalJSON is an implementation of the json.RawMessage interface and +// deserializes a [NumericDate] from a JSON representation, i.e. a +// [json.Number]. This number represents an UNIX epoch with either integer or +// non-integer seconds. +func (date *NumericDate) UnmarshalJSON(b []byte) (err error) { + var ( + number json.Number + f float64 + ) + + if err = json.Unmarshal(b, &number); err != nil { + return fmt.Errorf("could not parse NumericData: %w", err) + } + + if f, err = number.Float64(); err != nil { + return fmt.Errorf("could not convert json number value to float: %w", err) + } + + n := newNumericDateFromSeconds(f) + *date = *n + + return nil +} + +// ClaimStrings is basically just a slice of strings, but it can be either +// serialized from a string array or just a string. This type is necessary, +// since the "aud" claim can either be a single string or an array. +type ClaimStrings []string + +func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) { + var value interface{} + + if err = json.Unmarshal(data, &value); err != nil { + return err + } + + var aud []string + + switch v := value.(type) { + case string: + aud = append(aud, v) + case []string: + aud = ClaimStrings(v) + case []interface{}: + for _, vv := range v { + vs, ok := vv.(string) + if !ok { + return ErrInvalidType + } + aud = append(aud, vs) + } + case nil: + return nil + default: + return ErrInvalidType + } + + *s = aud + + return +} + +func (s ClaimStrings) MarshalJSON() (b []byte, err error) { + // This handles a special case in the JWT RFC. If the string array, e.g. + // used by the "aud" field, only contains one element, it MAY be serialized + // as a single string. This may or may not be desired based on the ecosystem + // of other JWT library used, so we make it configurable by the variable + // MarshalSingleStringAsArray. + if len(s) == 1 && !MarshalSingleStringAsArray { + return json.Marshal(s[0]) + } + + return json.Marshal([]string(s)) +} diff --git a/vendor/github.com/golang-jwt/jwt/v5/validator.go b/vendor/github.com/golang-jwt/jwt/v5/validator.go new file mode 100644 index 000000000..008ecd871 --- /dev/null +++ b/vendor/github.com/golang-jwt/jwt/v5/validator.go @@ -0,0 +1,316 @@ +package jwt + +import ( + "crypto/subtle" + "fmt" + "time" +) + +// ClaimsValidator is an interface that can be implemented by custom claims who +// wish to execute any additional claims validation based on +// application-specific logic. The Validate function is then executed in +// addition to the regular claims validation and any error returned is appended +// to the final validation result. +// +// type MyCustomClaims struct { +// Foo string `json:"foo"` +// jwt.RegisteredClaims +// } +// +// func (m MyCustomClaims) Validate() error { +// if m.Foo != "bar" { +// return errors.New("must be foobar") +// } +// return nil +// } +type ClaimsValidator interface { + Claims + Validate() error +} + +// Validator is the core of the new Validation API. It is automatically used by +// a [Parser] during parsing and can be modified with various parser options. +// +// The [NewValidator] function should be used to create an instance of this +// struct. +type Validator struct { + // leeway is an optional leeway that can be provided to account for clock skew. + leeway time.Duration + + // timeFunc is used to supply the current time that is needed for + // validation. If unspecified, this defaults to time.Now. + timeFunc func() time.Time + + // requireExp specifies whether the exp claim is required + requireExp bool + + // verifyIat specifies whether the iat (Issued At) claim will be verified. + // According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this + // only specifies the age of the token, but no validation check is + // necessary. However, if wanted, it can be checked if the iat is + // unrealistic, i.e., in the future. + verifyIat bool + + // expectedAud contains the audience this token expects. Supplying an empty + // string will disable aud checking. + expectedAud string + + // expectedIss contains the issuer this token expects. Supplying an empty + // string will disable iss checking. + expectedIss string + + // expectedSub contains the subject this token expects. Supplying an empty + // string will disable sub checking. + expectedSub string +} + +// NewValidator can be used to create a stand-alone validator with the supplied +// options. This validator can then be used to validate already parsed claims. +// +// Note: Under normal circumstances, explicitly creating a validator is not +// needed and can potentially be dangerous; instead functions of the [Parser] +// class should be used. +// +// The [Validator] is only checking the *validity* of the claims, such as its +// expiration time, but it does NOT perform *signature verification* of the +// token. +func NewValidator(opts ...ParserOption) *Validator { + p := NewParser(opts...) + return p.validator +} + +// Validate validates the given claims. It will also perform any custom +// validation if claims implements the [ClaimsValidator] interface. +// +// Note: It will NOT perform any *signature verification* on the token that +// contains the claims and expects that the [Claim] was already successfully +// verified. +func (v *Validator) Validate(claims Claims) error { + var ( + now time.Time + errs []error = make([]error, 0, 6) + err error + ) + + // Check, if we have a time func + if v.timeFunc != nil { + now = v.timeFunc() + } else { + now = time.Now() + } + + // We always need to check the expiration time, but usage of the claim + // itself is OPTIONAL by default. requireExp overrides this behavior + // and makes the exp claim mandatory. + if err = v.verifyExpiresAt(claims, now, v.requireExp); err != nil { + errs = append(errs, err) + } + + // We always need to check not-before, but usage of the claim itself is + // OPTIONAL. + if err = v.verifyNotBefore(claims, now, false); err != nil { + errs = append(errs, err) + } + + // Check issued-at if the option is enabled + if v.verifyIat { + if err = v.verifyIssuedAt(claims, now, false); err != nil { + errs = append(errs, err) + } + } + + // If we have an expected audience, we also require the audience claim + if v.expectedAud != "" { + if err = v.verifyAudience(claims, v.expectedAud, true); err != nil { + errs = append(errs, err) + } + } + + // If we have an expected issuer, we also require the issuer claim + if v.expectedIss != "" { + if err = v.verifyIssuer(claims, v.expectedIss, true); err != nil { + errs = append(errs, err) + } + } + + // If we have an expected subject, we also require the subject claim + if v.expectedSub != "" { + if err = v.verifySubject(claims, v.expectedSub, true); err != nil { + errs = append(errs, err) + } + } + + // Finally, we want to give the claim itself some possibility to do some + // additional custom validation based on a custom Validate function. + cvt, ok := claims.(ClaimsValidator) + if ok { + if err := cvt.Validate(); err != nil { + errs = append(errs, err) + } + } + + if len(errs) == 0 { + return nil + } + + return joinErrors(errs...) +} + +// verifyExpiresAt compares the exp claim in claims against cmp. This function +// will succeed if cmp < exp. Additional leeway is taken into account. +// +// If exp is not set, it will succeed if the claim is not required, +// otherwise ErrTokenRequiredClaimMissing will be returned. +// +// Additionally, if any error occurs while retrieving the claim, e.g., when its +// the wrong type, an ErrTokenUnverifiable error will be returned. +func (v *Validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) error { + exp, err := claims.GetExpirationTime() + if err != nil { + return err + } + + if exp == nil { + return errorIfRequired(required, "exp") + } + + return errorIfFalse(cmp.Before((exp.Time).Add(+v.leeway)), ErrTokenExpired) +} + +// verifyIssuedAt compares the iat claim in claims against cmp. This function +// will succeed if cmp >= iat. Additional leeway is taken into account. +// +// If iat is not set, it will succeed if the claim is not required, +// otherwise ErrTokenRequiredClaimMissing will be returned. +// +// Additionally, if any error occurs while retrieving the claim, e.g., when its +// the wrong type, an ErrTokenUnverifiable error will be returned. +func (v *Validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) error { + iat, err := claims.GetIssuedAt() + if err != nil { + return err + } + + if iat == nil { + return errorIfRequired(required, "iat") + } + + return errorIfFalse(!cmp.Before(iat.Add(-v.leeway)), ErrTokenUsedBeforeIssued) +} + +// verifyNotBefore compares the nbf claim in claims against cmp. This function +// will return true if cmp >= nbf. Additional leeway is taken into account. +// +// If nbf is not set, it will succeed if the claim is not required, +// otherwise ErrTokenRequiredClaimMissing will be returned. +// +// Additionally, if any error occurs while retrieving the claim, e.g., when its +// the wrong type, an ErrTokenUnverifiable error will be returned. +func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) error { + nbf, err := claims.GetNotBefore() + if err != nil { + return err + } + + if nbf == nil { + return errorIfRequired(required, "nbf") + } + + return errorIfFalse(!cmp.Before(nbf.Add(-v.leeway)), ErrTokenNotValidYet) +} + +// verifyAudience compares the aud claim against cmp. +// +// If aud is not set or an empty list, it will succeed if the claim is not required, +// otherwise ErrTokenRequiredClaimMissing will be returned. +// +// Additionally, if any error occurs while retrieving the claim, e.g., when its +// the wrong type, an ErrTokenUnverifiable error will be returned. +func (v *Validator) verifyAudience(claims Claims, cmp string, required bool) error { + aud, err := claims.GetAudience() + if err != nil { + return err + } + + if len(aud) == 0 { + return errorIfRequired(required, "aud") + } + + // use a var here to keep constant time compare when looping over a number of claims + result := false + + var stringClaims string + for _, a := range aud { + if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 { + result = true + } + stringClaims = stringClaims + a + } + + // case where "" is sent in one or many aud claims + if stringClaims == "" { + return errorIfRequired(required, "aud") + } + + return errorIfFalse(result, ErrTokenInvalidAudience) +} + +// verifyIssuer compares the iss claim in claims against cmp. +// +// If iss is not set, it will succeed if the claim is not required, +// otherwise ErrTokenRequiredClaimMissing will be returned. +// +// Additionally, if any error occurs while retrieving the claim, e.g., when its +// the wrong type, an ErrTokenUnverifiable error will be returned. +func (v *Validator) verifyIssuer(claims Claims, cmp string, required bool) error { + iss, err := claims.GetIssuer() + if err != nil { + return err + } + + if iss == "" { + return errorIfRequired(required, "iss") + } + + return errorIfFalse(iss == cmp, ErrTokenInvalidIssuer) +} + +// verifySubject compares the sub claim against cmp. +// +// If sub is not set, it will succeed if the claim is not required, +// otherwise ErrTokenRequiredClaimMissing will be returned. +// +// Additionally, if any error occurs while retrieving the claim, e.g., when its +// the wrong type, an ErrTokenUnverifiable error will be returned. +func (v *Validator) verifySubject(claims Claims, cmp string, required bool) error { + sub, err := claims.GetSubject() + if err != nil { + return err + } + + if sub == "" { + return errorIfRequired(required, "sub") + } + + return errorIfFalse(sub == cmp, ErrTokenInvalidSubject) +} + +// errorIfFalse returns the error specified in err, if the value is true. +// Otherwise, nil is returned. +func errorIfFalse(value bool, err error) error { + if value { + return nil + } else { + return err + } +} + +// errorIfRequired returns an ErrTokenRequiredClaimMissing error if required is +// true. Otherwise, nil is returned. +func errorIfRequired(required bool, claim string) error { + if required { + return newError(fmt.Sprintf("%s claim is required", claim), ErrTokenRequiredClaimMissing) + } else { + return nil + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 3f61cd914..9bb5024c8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -216,9 +216,9 @@ github.com/gobwas/glob/util/strings # github.com/gofrs/flock v0.8.1 ## explicit github.com/gofrs/flock -# github.com/golang-jwt/jwt v3.2.2+incompatible -## explicit -github.com/golang-jwt/jwt +# github.com/golang-jwt/jwt/v5 v5.2.1 +## explicit; go 1.18 +github.com/golang-jwt/jwt/v5 # github.com/golang/protobuf v1.5.3 ## explicit; go 1.9 github.com/golang/protobuf/jsonpb From dc9d18a5cea51107e723bb3d84628b37a89209aa Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:15:38 +0200 Subject: [PATCH 10/31] Update to github.com/golang-jwt/jwt/v5 --- http/middleware/response_header.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/http/middleware/response_header.go b/http/middleware/response_header.go index 13f73f180..da252e888 100644 --- a/http/middleware/response_header.go +++ b/http/middleware/response_header.go @@ -8,7 +8,7 @@ import ( "net/http" "strings" - jwt "github.com/golang-jwt/jwt" + jwt "github.com/golang-jwt/jwt/v5" ) // ClientIDHeaderName name of the HTTP header that is used for reporting @@ -34,6 +34,7 @@ func ClientID(next http.Handler) http.Handler { } type clientIDClaim struct { + jwt.MapClaims AuthorizedParty string `json:"azp"` } From eca90c7259fa0d6ab20df17aaf1e216b25731aab Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:16:21 +0200 Subject: [PATCH 11/31] gomod: Update github.com/gorilla/mux to v1.8.1 --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/gorilla/mux/.editorconfig | 20 ++++ vendor/github.com/gorilla/mux/.gitignore | 1 + vendor/github.com/gorilla/mux/AUTHORS | 8 -- vendor/github.com/gorilla/mux/LICENSE | 2 +- vendor/github.com/gorilla/mux/Makefile | 34 ++++++ vendor/github.com/gorilla/mux/README.md | 61 ++++++----- vendor/github.com/gorilla/mux/doc.go | 25 +++-- vendor/github.com/gorilla/mux/mux.go | 16 +-- vendor/github.com/gorilla/mux/regexp.go | 10 +- vendor/github.com/gorilla/mux/route.go | 109 +++++++++++++------- vendor/modules.txt | 4 +- 13 files changed, 190 insertions(+), 106 deletions(-) create mode 100644 vendor/github.com/gorilla/mux/.editorconfig create mode 100644 vendor/github.com/gorilla/mux/.gitignore delete mode 100644 vendor/github.com/gorilla/mux/AUTHORS create mode 100644 vendor/github.com/gorilla/mux/Makefile diff --git a/go.mod b/go.mod index 8802a1988..6af703e3d 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golangci/golangci-lint v1.51.2 github.com/google/uuid v1.6.0 - github.com/gorilla/mux v1.8.0 + github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/jpillora/backoff v1.0.0 diff --git a/go.sum b/go.sum index a6cb6b0bf..4282d7839 100644 --- a/go.sum +++ b/go.sum @@ -323,8 +323,8 @@ github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 h1:9alfqbrhuD+9fLZ4iaAVwhlp5PEhmnBt7yvK2Oy5C1U= github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= diff --git a/vendor/github.com/gorilla/mux/.editorconfig b/vendor/github.com/gorilla/mux/.editorconfig new file mode 100644 index 000000000..c6b74c3e0 --- /dev/null +++ b/vendor/github.com/gorilla/mux/.editorconfig @@ -0,0 +1,20 @@ +; https://editorconfig.org/ + +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false + +eclint_indent_style = unset \ No newline at end of file diff --git a/vendor/github.com/gorilla/mux/.gitignore b/vendor/github.com/gorilla/mux/.gitignore new file mode 100644 index 000000000..84039fec6 --- /dev/null +++ b/vendor/github.com/gorilla/mux/.gitignore @@ -0,0 +1 @@ +coverage.coverprofile diff --git a/vendor/github.com/gorilla/mux/AUTHORS b/vendor/github.com/gorilla/mux/AUTHORS deleted file mode 100644 index b722392ee..000000000 --- a/vendor/github.com/gorilla/mux/AUTHORS +++ /dev/null @@ -1,8 +0,0 @@ -# This is the official list of gorilla/mux authors for copyright purposes. -# -# Please keep the list sorted. - -Google LLC (https://opensource.google.com/) -Kamil Kisielk -Matt Silverlock -Rodrigo Moraes (https://github.com/moraes) diff --git a/vendor/github.com/gorilla/mux/LICENSE b/vendor/github.com/gorilla/mux/LICENSE index 6903df638..bb9d80bc9 100644 --- a/vendor/github.com/gorilla/mux/LICENSE +++ b/vendor/github.com/gorilla/mux/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. +Copyright (c) 2023 The Gorilla Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/gorilla/mux/Makefile b/vendor/github.com/gorilla/mux/Makefile new file mode 100644 index 000000000..98f5ab75f --- /dev/null +++ b/vendor/github.com/gorilla/mux/Makefile @@ -0,0 +1,34 @@ +GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') +GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest + +GO_SEC=$(shell which gosec 2> /dev/null || echo '') +GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest + +GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') +GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest + +.PHONY: golangci-lint +golangci-lint: + $(if $(GO_LINT), ,go install $(GO_LINT_URI)) + @echo "##### Running golangci-lint" + golangci-lint run -v + +.PHONY: gosec +gosec: + $(if $(GO_SEC), ,go install $(GO_SEC_URI)) + @echo "##### Running gosec" + gosec ./... + +.PHONY: govulncheck +govulncheck: + $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) + @echo "##### Running govulncheck" + govulncheck ./... + +.PHONY: verify +verify: golangci-lint gosec govulncheck + +.PHONY: test +test: + @echo "##### Running tests" + go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... \ No newline at end of file diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md index 35eea9f10..382513d57 100644 --- a/vendor/github.com/gorilla/mux/README.md +++ b/vendor/github.com/gorilla/mux/README.md @@ -1,12 +1,12 @@ # gorilla/mux -[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) -[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux) -[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) +![testing](https://github.com/gorilla/mux/actions/workflows/test.yml/badge.svg) +[![codecov](https://codecov.io/github/gorilla/mux/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/mux) +[![godoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) +[![sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) -![Gorilla Logo](https://cloud-cdn.questionable.services/gorilla-icon-64.png) -https://www.gorillatoolkit.org/pkg/mux +![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5) Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to their respective handler. @@ -247,32 +247,25 @@ type spaHandler struct { // file located at the index path on the SPA handler will be served. This // is suitable behavior for serving an SPA (single page application). func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // get the absolute path to prevent directory traversal - path, err := filepath.Abs(r.URL.Path) - if err != nil { - // if we failed to get the absolute path respond with a 400 bad request - // and stop - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - // prepend the path with the path to the static directory - path = filepath.Join(h.staticPath, path) + // Join internally call path.Clean to prevent directory traversal + path := filepath.Join(h.staticPath, r.URL.Path) - // check whether a file exists at the given path - _, err = os.Stat(path) - if os.IsNotExist(err) { - // file does not exist, serve index.html + // check whether a file exists or is a directory at the given path + fi, err := os.Stat(path) + if os.IsNotExist(err) || fi.IsDir() { + // file does not exist or path is a directory, serve index.html http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath)) return - } else if err != nil { - // if we got an error (that wasn't that the file doesn't exist) stating the - // file, return a 500 internal server error and stop + } + + if err != nil { + // if we got an error (that wasn't that the file doesn't exist) stating the + // file, return a 500 internal server error and stop http.Error(w, err.Error(), http.StatusInternalServerError) - return + return } - // otherwise, use http.FileServer to serve the static dir + // otherwise, use http.FileServer to serve the static file http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r) } @@ -375,6 +368,19 @@ url, err := r.Get("article").URL("subdomain", "news", "id", "42") ``` +To find all the required variables for a given route when calling `URL()`, the method `GetVarNames()` is available: +```go +r := mux.NewRouter() +r.Host("{domain}"). + Path("/{group}/{item_id}"). + Queries("some_data1", "{some_data1}"). + Queries("some_data2", "{some_data2}"). + Name("article") + +// Will print [domain group item_id some_data1 some_data2] +fmt.Println(r.Get("article").GetVarNames()) + +``` ### Walking Routes The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example, @@ -572,7 +578,7 @@ func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler r := mux.NewRouter() r.HandleFunc("/", handler) -amw := authenticationMiddleware{} +amw := authenticationMiddleware{tokenUsers: make(map[string]string)} amw.Populate() r.Use(amw.Middleware) @@ -758,7 +764,8 @@ func TestMetricsHandler(t *testing.T) { rr := httptest.NewRecorder() - // Need to create a router that we can pass the request through so that the vars will be added to the context + // To add the vars to the context, + // we need to create a router through which we can pass the request. router := mux.NewRouter() router.HandleFunc("/metrics/{type}", MetricsHandler) router.ServeHTTP(rr, req) diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go index bd5a38b55..80601351f 100644 --- a/vendor/github.com/gorilla/mux/doc.go +++ b/vendor/github.com/gorilla/mux/doc.go @@ -10,18 +10,18 @@ http.ServeMux, mux.Router matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are: - * Requests can be matched based on URL host, path, path prefix, schemes, - header and query values, HTTP methods or using custom matchers. - * URL hosts, paths and query values can have variables with an optional - regular expression. - * Registered URLs can be built, or "reversed", which helps maintaining - references to resources. - * Routes can be used as subrouters: nested routes are only tested if the - parent route matches. This is useful to define groups of routes that - share common conditions like a host, a path prefix or other repeated - attributes. As a bonus, this optimizes request matching. - * It implements the http.Handler interface so it is compatible with the - standard http.ServeMux. + - Requests can be matched based on URL host, path, path prefix, schemes, + header and query values, HTTP methods or using custom matchers. + - URL hosts, paths and query values can have variables with an optional + regular expression. + - Registered URLs can be built, or "reversed", which helps maintaining + references to resources. + - Routes can be used as subrouters: nested routes are only tested if the + parent route matches. This is useful to define groups of routes that + share common conditions like a host, a path prefix or other repeated + attributes. As a bonus, this optimizes request matching. + - It implements the http.Handler interface so it is compatible with the + standard http.ServeMux. Let's start registering a couple of URL paths and handlers: @@ -301,6 +301,5 @@ A more complex authentication middleware, which maps session token to users, cou r.Use(amw.Middleware) Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. - */ package mux diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go index 782a34b22..1e089906f 100644 --- a/vendor/github.com/gorilla/mux/mux.go +++ b/vendor/github.com/gorilla/mux/mux.go @@ -31,24 +31,26 @@ func NewRouter() *Router { // It implements the http.Handler interface, so it can be registered to serve // requests: // -// var router = mux.NewRouter() +// var router = mux.NewRouter() // -// func main() { -// http.Handle("/", router) -// } +// func main() { +// http.Handle("/", router) +// } // // Or, for Google App Engine, register it in a init() function: // -// func init() { -// http.Handle("/", router) -// } +// func init() { +// http.Handle("/", router) +// } // // This will send all incoming requests to the router. type Router struct { // Configurable Handler to be used when no route matches. + // This can be used to render your own 404 Not Found errors. NotFoundHandler http.Handler // Configurable Handler to be used when the request method does not match the route. + // This can be used to render your own 405 Method Not Allowed errors. MethodNotAllowedHandler http.Handler // Routes to be matched, in order. diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go index 0144842bb..5d05cfa0e 100644 --- a/vendor/github.com/gorilla/mux/regexp.go +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -22,10 +22,10 @@ type routeRegexpOptions struct { type regexpType int const ( - regexpTypePath regexpType = 0 - regexpTypeHost regexpType = 1 - regexpTypePrefix regexpType = 2 - regexpTypeQuery regexpType = 3 + regexpTypePath regexpType = iota + regexpTypeHost + regexpTypePrefix + regexpTypeQuery ) // newRouteRegexp parses a route template and returns a routeRegexp, @@ -195,7 +195,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { // url builds a URL part using the given values. func (r *routeRegexp) url(values map[string]string) (string, error) { - urlValues := make([]interface{}, len(r.varsN), len(r.varsN)) + urlValues := make([]interface{}, len(r.varsN)) for k, v := range r.varsN { value, ok := values[v] if !ok { diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go index 750afe570..e8f11df22 100644 --- a/vendor/github.com/gorilla/mux/route.go +++ b/vendor/github.com/gorilla/mux/route.go @@ -64,8 +64,18 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool { match.MatchErr = nil } - matchErr = nil + matchErr = nil // nolint:ineffassign return false + } else { + // Multiple routes may share the same path but use different HTTP methods. For instance: + // Route 1: POST "/users/{id}". + // Route 2: GET "/users/{id}", parameters: "id": "[0-9]+". + // + // The router must handle these cases correctly. For a GET request to "/users/abc" with "id" as "-2", + // The router should return a "Not Found" error as no route fully matches this request. + if match.MatchErr == ErrMethodMismatch { + match.MatchErr = nil + } } } @@ -230,9 +240,9 @@ func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool { // Headers adds a matcher for request header values. // It accepts a sequence of key/value pairs to be matched. For example: // -// r := mux.NewRouter() -// r.Headers("Content-Type", "application/json", -// "X-Requested-With", "XMLHttpRequest") +// r := mux.NewRouter().NewRoute() +// r.Headers("Content-Type", "application/json", +// "X-Requested-With", "XMLHttpRequest") // // The above route will only match if both request header values match. // If the value is an empty string, it will match any value if the key is set. @@ -255,9 +265,9 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { // HeadersRegexp accepts a sequence of key/value pairs, where the value has regex // support. For example: // -// r := mux.NewRouter() -// r.HeadersRegexp("Content-Type", "application/(text|json)", -// "X-Requested-With", "XMLHttpRequest") +// r := mux.NewRouter().NewRoute() +// r.HeadersRegexp("Content-Type", "application/(text|json)", +// "X-Requested-With", "XMLHttpRequest") // // The above route will only match if both the request header matches both regular expressions. // If the value is an empty string, it will match any value if the key is set. @@ -283,10 +293,10 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route { // // For example: // -// r := mux.NewRouter() -// r.Host("www.example.com") -// r.Host("{subdomain}.domain.com") -// r.Host("{subdomain:[a-z]+}.domain.com") +// r := mux.NewRouter().NewRoute() +// r.Host("www.example.com") +// r.Host("{subdomain}.domain.com") +// r.Host("{subdomain:[a-z]+}.domain.com") // // Variable names must be unique in a given route. They can be retrieved // calling mux.Vars(request). @@ -342,11 +352,11 @@ func (r *Route) Methods(methods ...string) *Route { // // For example: // -// r := mux.NewRouter() -// r.Path("/products/").Handler(ProductsHandler) -// r.Path("/products/{key}").Handler(ProductsHandler) -// r.Path("/articles/{category}/{id:[0-9]+}"). -// Handler(ArticleHandler) +// r := mux.NewRouter().NewRoute() +// r.Path("/products/").Handler(ProductsHandler) +// r.Path("/products/{key}").Handler(ProductsHandler) +// r.Path("/articles/{category}/{id:[0-9]+}"). +// Handler(ArticleHandler) // // Variable names must be unique in a given route. They can be retrieved // calling mux.Vars(request). @@ -377,8 +387,8 @@ func (r *Route) PathPrefix(tpl string) *Route { // It accepts a sequence of key/value pairs. Values may define variables. // For example: // -// r := mux.NewRouter() -// r.Queries("foo", "bar", "id", "{id:[0-9]+}") +// r := mux.NewRouter().NewRoute() +// r.Queries("foo", "bar", "id", "{id:[0-9]+}") // // The above route will only match if the URL contains the defined queries // values, e.g.: ?foo=bar&id=42. @@ -473,11 +483,11 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route { // // It will test the inner routes only if the parent route matched. For example: // -// r := mux.NewRouter() -// s := r.Host("www.example.com").Subrouter() -// s.HandleFunc("/products/", ProductsHandler) -// s.HandleFunc("/products/{key}", ProductHandler) -// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) +// r := mux.NewRouter().NewRoute() +// s := r.Host("www.example.com").Subrouter() +// s.HandleFunc("/products/", ProductsHandler) +// s.HandleFunc("/products/{key}", ProductHandler) +// s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler) // // Here, the routes registered in the subrouter won't be tested if the host // doesn't match. @@ -497,36 +507,36 @@ func (r *Route) Subrouter() *Router { // It accepts a sequence of key/value pairs for the route variables. For // example, given this route: // -// r := mux.NewRouter() -// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). -// Name("article") +// r := mux.NewRouter() +// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Name("article") // // ...a URL for it can be built using: // -// url, err := r.Get("article").URL("category", "technology", "id", "42") +// url, err := r.Get("article").URL("category", "technology", "id", "42") // // ...which will return an url.URL with the following path: // -// "/articles/technology/42" +// "/articles/technology/42" // // This also works for host variables: // -// r := mux.NewRouter() -// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). -// Host("{subdomain}.domain.com"). -// Name("article") +// r := mux.NewRouter() +// r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). +// Host("{subdomain}.domain.com"). +// Name("article") // -// // url.String() will be "http://news.domain.com/articles/technology/42" -// url, err := r.Get("article").URL("subdomain", "news", -// "category", "technology", -// "id", "42") +// // url.String() will be "http://news.domain.com/articles/technology/42" +// url, err := r.Get("article").URL("subdomain", "news", +// "category", "technology", +// "id", "42") // // The scheme of the resulting url will be the first argument that was passed to Schemes: // -// // url.String() will be "https://example.com" -// r := mux.NewRouter() -// url, err := r.Host("example.com") -// .Schemes("https", "http").URL() +// // url.String() will be "https://example.com" +// r := mux.NewRouter().NewRoute() +// url, err := r.Host("example.com") +// .Schemes("https", "http").URL() // // All variables defined in the route are required, and their values must // conform to the corresponding patterns. @@ -718,6 +728,25 @@ func (r *Route) GetHostTemplate() (string, error) { return r.regexp.host.template, nil } +// GetVarNames returns the names of all variables added by regexp matchers +// These can be used to know which route variables should be passed into r.URL() +func (r *Route) GetVarNames() ([]string, error) { + if r.err != nil { + return nil, r.err + } + var varNames []string + if r.regexp.host != nil { + varNames = append(varNames, r.regexp.host.varsN...) + } + if r.regexp.path != nil { + varNames = append(varNames, r.regexp.path.varsN...) + } + for _, regx := range r.regexp.queries { + varNames = append(varNames, regx.varsN...) + } + return varNames, nil +} + // prepareVars converts the route variable pairs into a map. If the route has a // BuildVarsFunc, it is invoked. func (r *Route) prepareVars(pairs ...string) (map[string]string, error) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 9bb5024c8..77fff565c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -304,8 +304,8 @@ github.com/google/uuid # github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 ## explicit; go 1.14 github.com/gordonklaus/ineffassign/pkg/ineffassign -# github.com/gorilla/mux v1.8.0 -## explicit; go 1.12 +# github.com/gorilla/mux v1.8.1 +## explicit; go 1.20 github.com/gorilla/mux # github.com/gostaticanalysis/analysisutil v0.7.1 ## explicit; go 1.16 From 5756a8b7e489dc8f857f86fc6474fe58b6eb8ec0 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:17:21 +0200 Subject: [PATCH 12/31] gomod: Update github.com/grpc-ecosystem/go-grpc-middleware --- go.mod | 4 +- go.sum | 16 +- .../go-grpc-middleware/.travis.yml | 16 -- .../go-grpc-middleware/CHANGELOG.md | 51 ----- .../go-grpc-middleware/README.md | 55 ++--- .../go-grpc-middleware/chain.go | 130 ++++++++---- .../go-grpc-middleware/retry/doc.go | 2 +- .../go-grpc-middleware/retry/retry.go | 14 +- .../util/metautils/nicemd.go | 6 +- vendor/go.uber.org/zap/CHANGELOG.md | 32 +++ vendor/go.uber.org/zap/buffer/buffer.go | 18 ++ vendor/go.uber.org/zap/logger.go | 9 +- vendor/go.uber.org/zap/options.go | 8 + vendor/go.uber.org/zap/sugar.go | 4 +- .../zap/zapcore/buffered_write_syncer.go | 188 ++++++++++++++++++ vendor/go.uber.org/zap/zapcore/clock.go | 50 +++++ vendor/go.uber.org/zap/zapcore/entry.go | 4 +- vendor/modules.txt | 4 +- 18 files changed, 444 insertions(+), 167 deletions(-) delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/.travis.yml delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/CHANGELOG.md create mode 100644 vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go create mode 100644 vendor/go.uber.org/zap/zapcore/clock.go diff --git a/go.mod b/go.mod index 6af703e3d..3969aa586 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/golangci/golangci-lint v1.51.2 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/jpillora/backoff v1.0.0 github.com/mattn/go-isatty v0.0.17 @@ -207,7 +207,7 @@ require ( gitlab.com/bosi/decorder v0.2.3 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.17.0 // indirect + go.uber.org/zap v1.18.1 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 // indirect diff --git a/go.sum b/go.sum index 4282d7839..cdede208c 100644 --- a/go.sum +++ b/go.sum @@ -340,8 +340,8 @@ github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -688,15 +688,14 @@ 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.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 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.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= 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= @@ -739,6 +738,8 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu 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/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/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= @@ -882,6 +883,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc 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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/.travis.yml b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/.travis.yml deleted file mode 100644 index fc198d882..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -sudo: false -language: go -go: - - 1.13.x - - 1.14.x - - 1.15.x - -env: - global: - - GO111MODULE=on - -script: - - make test - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/CHANGELOG.md b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/CHANGELOG.md deleted file mode 100644 index 6eeb7e2dc..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/CHANGELOG.md +++ /dev/null @@ -1,51 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). - -Types of changes: -- `Added` for new features. -- `Changed` for changes in existing functionality. -- `Deprecated` for soon-to-be removed features. -- `Removed` for now removed features. -- `Fixed` for any bug fixes. -- `Security` in case of vulnerabilities. - -## [Unreleased] - -### Added - -- [#223](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/223) Add go-kit logging middleware - [adrien-f](https://github.com/adrien-f) - -## [v1.1.0] - 2019-09-12 -### Added -- [#226](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/226) Support for go modules. -- [#221](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/221) logging/zap add support for gRPC LoggerV2 - [kush-patel-hs](https://github.com/kush-patel-hs) -- [#181](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/181) Rate Limit support - [ceshihao](https://github.com/ceshihao) -- [#161](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/161) Retry on server stream call - [lonnblad](https://github.com/lonnblad) -- [#152](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/152) Exponential backoff functions - [polyfloyd](https://github.com/polyfloyd) -- [#147](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/147) Jaeger support for ctxtags extraction - [vporoshok](https://github.com/vporoshok) -- [#184](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/184) ctxTags identifies if the call was sampled - -### Deprecated -- [#201](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/201) `golang.org/x/net/context` - [houz42](https://github.com/houz42) -- [#183](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/183) Documentation Generation in favour of . - -### Fixed -- [172](https://github.com/grpc-ecosystem/go-grpc-middleware/pull/172) Passing ctx into retry and recover - [johanbrandhorst](https://github.com/johanbrandhorst) -- Numerious documentation fixes. - -## v1.0.0 - 2018-05-08 -### Added -- grpc_auth -- grpc_ctxtags -- grpc_zap -- grpc_logrus -- grpc_opentracing -- grpc_retry -- grpc_validator -- grpc_recovery - -[Unreleased]: https://github.com/grpc-ecosystem/go-grpc-middleware/compare/v1.1.0...HEAD -[v1.1.0]: https://github.com/grpc-ecosystem/go-grpc-middleware/compare/v1.0.0...v1.1.0 diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/README.md b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/README.md index 814e15517..a12b40904 100644 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/README.md +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/README.md @@ -7,16 +7,23 @@ [![codecov](https://codecov.io/gh/grpc-ecosystem/go-grpc-middleware/branch/master/graph/badge.svg)](https://codecov.io/gh/grpc-ecosystem/go-grpc-middleware) [![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) [![quality: production](https://img.shields.io/badge/quality-production-orange.svg)](#status) -[![Slack](https://img.shields.io/badge/slack-%23grpc--middleware-brightgreen)](https://slack.com/share/IRUQCFC23/9Tm7hxRFVKKNoajQfMOcUiIk/enQtODc4ODI4NTIyMDcxLWM5NDA0ZTE4Njg5YjRjYWZkMTI5MzQwNDY3YzBjMzE1YzdjOGM5ZjI1NDNiM2JmNzI2YjM5ODE5OTRiNTEyOWE) +[![Slack](https://img.shields.io/badge/slack-%23grpc--middleware-brightgreen)](https://gophers.slack.com/archives/CNJL30P4P) [gRPC Go](https://github.com/grpc/grpc-go) Middleware: interceptors, helpers, utilities. +## ⚠️ Status + +Version [v2](https://github.com/grpc-ecosystem/go-grpc-middleware/tree/v2) is about to be released, with migration guide, which will replace v1. Try v2 and give us feedback! + +Version v1 is currently in deprecation mode, which means only critical and safety bug fixes will be merged. + + ## Middleware [gRPC Go](https://github.com/grpc/grpc-go) recently acquired support for -Interceptors, i.e. [middleware](https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.gv7tdlghs) +Interceptors, i.e. [middleware](https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81#.gv7tdlghs) that is executed either on the gRPC Server before the request is passed onto the user's application logic, or on the gRPC client around the user call. It is a perfect way to implement -common patterns: auth, logging, message, validation, retries or monitoring. +common patterns: auth, logging, message, validation, retries, or monitoring. These are generic building blocks that make it easy to build multiple microservices easily. The purpose of this repository is to act as a go-to point for such reusable functionality. It contains @@ -29,57 +36,57 @@ import "github.com/grpc-ecosystem/go-grpc-middleware" myServer := grpc.NewServer( grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( - grpc_recovery.StreamServerInterceptor(), grpc_ctxtags.StreamServerInterceptor(), grpc_opentracing.StreamServerInterceptor(), grpc_prometheus.StreamServerInterceptor, grpc_zap.StreamServerInterceptor(zapLogger), grpc_auth.StreamServerInterceptor(myAuthFunction), + grpc_recovery.StreamServerInterceptor(), )), grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer( - grpc_recovery.UnaryServerInterceptor(), grpc_ctxtags.UnaryServerInterceptor(), grpc_opentracing.UnaryServerInterceptor(), grpc_prometheus.UnaryServerInterceptor, grpc_zap.UnaryServerInterceptor(zapLogger), grpc_auth.UnaryServerInterceptor(myAuthFunction), + grpc_recovery.UnaryServerInterceptor(), )), ) ``` ## Interceptors -*Please send a PR to add new interceptors or middleware to this list* +_Please send a PR to add new interceptors or middleware to this list_ #### Auth - * [`grpc_auth`](auth) - a customizable (via `AuthFunc`) piece of auth middleware + +- [`grpc_auth`](auth) - a customizable (via `AuthFunc`) piece of auth middleware #### Logging - * [`grpc_ctxtags`](tags/) - a library that adds a `Tag` map to context, with data populated from request body - * [`grpc_zap`](logging/zap/) - integration of [zap](https://github.com/uber-go/zap) logging library into gRPC handlers. - * [`grpc_logrus`](logging/logrus/) - integration of [logrus](https://github.com/sirupsen/logrus) logging library into gRPC handlers. - * [`grpc_kit`](logging/kit/) - integration of [go-kit](https://github.com/go-kit/kit/tree/master/log) logging library into gRPC handlers. - * [`grpc_grpc_logsettable`](logging/settable/) - a wrapper around `grpclog.LoggerV2` that allows to replace loggers in runtime (thread-safe). + +- [`grpc_ctxtags`](tags/) - a library that adds a `Tag` map to context, with data populated from request body +- [`grpc_zap`](logging/zap/) - integration of [zap](https://github.com/uber-go/zap) logging library into gRPC handlers. +- [`grpc_logrus`](logging/logrus/) - integration of [logrus](https://github.com/sirupsen/logrus) logging library into gRPC handlers. +- [`grpc_kit`](logging/kit/) - integration of [go-kit/log](https://github.com/go-kit/log) logging library into gRPC handlers. +- [`grpc_grpc_logsettable`](logging/settable/) - a wrapper around `grpclog.LoggerV2` that allows to replace loggers in runtime (thread-safe). #### Monitoring - * [`grpc_prometheus`⚡](https://github.com/grpc-ecosystem/go-grpc-prometheus) - Prometheus client-side and server-side monitoring middleware - * [`otgrpc`⚡](https://github.com/grpc-ecosystem/grpc-opentracing/tree/master/go/otgrpc) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors - * [`grpc_opentracing`](tracing/opentracing) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors with support for streaming and handler-returned tags -#### Client - * [`grpc_retry`](retry/) - a generic gRPC response code retry mechanism, client-side middleware +- [`grpc_prometheus`⚡](https://github.com/grpc-ecosystem/go-grpc-prometheus) - Prometheus client-side and server-side monitoring middleware +- [`otgrpc`⚡](https://github.com/grpc-ecosystem/grpc-opentracing/tree/master/go/otgrpc) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors +- [`grpc_opentracing`](tracing/opentracing) - [OpenTracing](http://opentracing.io/) client-side and server-side interceptors with support for streaming and handler-returned tags +- [`otelgrpc`](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation/google.golang.org/grpc/otelgrpc) - [OpenTelemetry](https://opentelemetry.io/) client-side and server-side interceptors -#### Server - * [`grpc_validator`](validator/) - codegen inbound message validation from `.proto` options - * [`grpc_recovery`](recovery/) - turn panics into gRPC errors - * [`ratelimit`](ratelimit/) - grpc rate limiting by your own limiter +#### Client +- [`grpc_retry`](retry/) - a generic gRPC response code retry mechanism, client-side middleware -## Status +#### Server -This code has been running in *production* since May 2016 as the basis of the gRPC micro services stack at [Improbable](https://improbable.io). +- [`grpc_validator`](validator/) - codegen inbound message validation from `.proto` options +- [`grpc_recovery`](recovery/) - turn panics into gRPC errors +- [`ratelimit`](ratelimit/) - grpc rate limiting by your own limiter -Additional tooling will be added, and contributions are welcome. ## License diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/chain.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/chain.go index ea3738b89..407d9332c 100644 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/chain.go +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/chain.go @@ -16,22 +16,41 @@ import ( // Execution is done in left-to-right order, including passing of context. // For example ChainUnaryServer(one, two, three) will execute one before two before three, and three // will see context changes of one and two. +// +// While this can be useful in some scenarios, it is generally advisable to use google.golang.org/grpc.ChainUnaryInterceptor directly. func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor { n := len(interceptors) - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - chainer := func(currentInter grpc.UnaryServerInterceptor, currentHandler grpc.UnaryHandler) grpc.UnaryHandler { - return func(currentCtx context.Context, currentReq interface{}) (interface{}, error) { - return currentInter(currentCtx, currentReq, info, currentHandler) - } + // Dummy interceptor maintained for backward compatibility to avoid returning nil. + if n == 0 { + return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return handler(ctx, req) } + } - chainedHandler := handler - for i := n - 1; i >= 0; i-- { - chainedHandler = chainer(interceptors[i], chainedHandler) - } + // The degenerate case, just return the single wrapped interceptor directly. + if n == 1 { + return interceptors[0] + } - return chainedHandler(ctx, req) + // Return a function which satisfies the interceptor interface, and which is + // a closure over the given list of interceptors to be chained. + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + currHandler := handler + // Iterate backwards through all interceptors except the first (outermost). + // Wrap each one in a function which satisfies the handler interface, but + // is also a closure over the `info` and `handler` parameters. Then pass + // each pseudo-handler to the next outer interceptor as the handler to be called. + for i := n - 1; i > 0; i-- { + // Rebind to loop-local vars so they can be closed over. + innerHandler, i := currHandler, i + currHandler = func(currentCtx context.Context, currentReq interface{}) (interface{}, error) { + return interceptors[i](currentCtx, currentReq, info, innerHandler) + } + } + // Finally return the result of calling the outermost interceptor with the + // outermost pseudo-handler created above as its handler. + return interceptors[0](ctx, req, info, currHandler) } } @@ -40,22 +59,31 @@ func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnarySer // Execution is done in left-to-right order, including passing of context. // For example ChainUnaryServer(one, two, three) will execute one before two before three. // If you want to pass context between interceptors, use WrapServerStream. +// +// While this can be useful in some scenarios, it is generally advisable to use google.golang.org/grpc.ChainStreamInterceptor directly. func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor { n := len(interceptors) - return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - chainer := func(currentInter grpc.StreamServerInterceptor, currentHandler grpc.StreamHandler) grpc.StreamHandler { - return func(currentSrv interface{}, currentStream grpc.ServerStream) error { - return currentInter(currentSrv, currentStream, info, currentHandler) - } + // Dummy interceptor maintained for backward compatibility to avoid returning nil. + if n == 0 { + return func(srv interface{}, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + return handler(srv, stream) } + } - chainedHandler := handler - for i := n - 1; i >= 0; i-- { - chainedHandler = chainer(interceptors[i], chainedHandler) - } + if n == 1 { + return interceptors[0] + } - return chainedHandler(srv, ss) + return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + currHandler := handler + for i := n - 1; i > 0; i-- { + innerHandler, i := currHandler, i + currHandler = func(currentSrv interface{}, currentStream grpc.ServerStream) error { + return interceptors[i](currentSrv, currentStream, info, innerHandler) + } + } + return interceptors[0](srv, stream, info, currHandler) } } @@ -66,19 +94,26 @@ func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.Stream func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor { n := len(interceptors) - return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - chainer := func(currentInter grpc.UnaryClientInterceptor, currentInvoker grpc.UnaryInvoker) grpc.UnaryInvoker { - return func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error { - return currentInter(currentCtx, currentMethod, currentReq, currentRepl, currentConn, currentInvoker, currentOpts...) - } + // Dummy interceptor maintained for backward compatibility to avoid returning nil. + if n == 0 { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + return invoker(ctx, method, req, reply, cc, opts...) } + } - chainedInvoker := invoker - for i := n - 1; i >= 0; i-- { - chainedInvoker = chainer(interceptors[i], chainedInvoker) - } + if n == 1 { + return interceptors[0] + } - return chainedInvoker(ctx, method, req, reply, cc, opts...) + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + currInvoker := invoker + for i := n - 1; i > 0; i-- { + innerInvoker, i := currInvoker, i + currInvoker = func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error { + return interceptors[i](currentCtx, currentMethod, currentReq, currentRepl, currentConn, innerInvoker, currentOpts...) + } + } + return interceptors[0](ctx, method, req, reply, cc, currInvoker, opts...) } } @@ -89,19 +124,26 @@ func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryCli func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor { n := len(interceptors) - return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { - chainer := func(currentInter grpc.StreamClientInterceptor, currentStreamer grpc.Streamer) grpc.Streamer { - return func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) { - return currentInter(currentCtx, currentDesc, currentConn, currentMethod, currentStreamer, currentOpts...) - } + // Dummy interceptor maintained for backward compatibility to avoid returning nil. + if n == 0 { + return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return streamer(ctx, desc, cc, method, opts...) } + } - chainedStreamer := streamer - for i := n - 1; i >= 0; i-- { - chainedStreamer = chainer(interceptors[i], chainedStreamer) - } + if n == 1 { + return interceptors[0] + } - return chainedStreamer(ctx, desc, cc, method, opts...) + return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + currStreamer := streamer + for i := n - 1; i > 0; i-- { + innerStreamer, i := currStreamer, i + currStreamer = func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) { + return interceptors[i](currentCtx, currentDesc, currentConn, currentMethod, innerStreamer, currentOpts...) + } + } + return interceptors[0](ctx, desc, cc, method, currStreamer, opts...) } } @@ -109,12 +151,16 @@ func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.Stream // // WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors. // Basically syntactic sugar. +// +// Deprecated: use google.golang.org/grpc.ChainUnaryInterceptor instead. func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption { - return grpc.UnaryInterceptor(ChainUnaryServer(interceptors...)) + return grpc.ChainUnaryInterceptor(interceptors...) } // WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors. // Basically syntactic sugar. +// +// Deprecated: use google.golang.org/grpc.ChainStreamInterceptor instead. func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption { - return grpc.StreamInterceptor(ChainStreamServer(interceptors...)) + return grpc.ChainStreamInterceptor(interceptors...) } diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/doc.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/doc.go index afd924a14..f8ba7198a 100644 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/doc.go +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/doc.go @@ -18,7 +18,7 @@ Other default options are: retry on `ResourceExhausted` and `Unavailable` gRPC c linear backoff with 10% jitter. For chained interceptors, the retry interceptor will call every interceptor that follows it -whenever when a retry happens. +whenever a retry happens. Please see examples for more advanced use. */ diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/retry.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/retry.go index 62d831201..003bbd906 100644 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/retry.go +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/retry/retry.go @@ -5,8 +5,8 @@ package grpc_retry import ( "context" - "fmt" "io" + "strconv" "sync" "time" @@ -136,7 +136,6 @@ func StreamClientInterceptor(optFuncs ...CallOption) grpc.StreamClientIntercepto type serverStreamingRetryingStream struct { grpc.ClientStream bufferedSends []interface{} // single message that the client can sen - receivedGood bool // indicates whether any prior receives were successful wasClosedSend bool // indicates that CloseSend was closed parentCtx context.Context callOpts *options @@ -209,17 +208,8 @@ func (s *serverStreamingRetryingStream) RecvMsg(m interface{}) error { } func (s *serverStreamingRetryingStream) receiveMsgAndIndicateRetry(m interface{}) (bool, error) { - s.mu.RLock() - wasGood := s.receivedGood - s.mu.RUnlock() err := s.getStream().RecvMsg(m) if err == nil || err == io.EOF { - s.mu.Lock() - s.receivedGood = true - s.mu.Unlock() - return false, err - } else if wasGood { - // previous RecvMsg in the stream succeeded, no retry logic should interfere return false, err } if isContextError(err) { @@ -303,7 +293,7 @@ func perCallContext(parentCtx context.Context, callOpts *options, attempt uint) ctx, _ = context.WithTimeout(ctx, callOpts.perCallTimeout) } if attempt > 0 && callOpts.includeHeader { - mdClone := metautils.ExtractOutgoing(ctx).Clone().Set(AttemptMetadataKey, fmt.Sprintf("%d", attempt)) + mdClone := metautils.ExtractOutgoing(ctx).Clone().Set(AttemptMetadataKey, strconv.FormatUint(uint64(attempt), 10)) ctx = mdClone.ToOutgoing(ctx) } return ctx diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/util/metautils/nicemd.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/util/metautils/nicemd.go index 1c60585dd..15225d710 100644 --- a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/util/metautils/nicemd.go +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/util/metautils/nicemd.go @@ -10,7 +10,7 @@ import ( "google.golang.org/grpc/metadata" ) -// NiceMD is a convenience wrapper definiting extra functions on the metadata. +// NiceMD is a convenience wrapper defining extra functions on the metadata. type NiceMD metadata.MD // ExtractIncoming extracts an inbound metadata from the server-side context. @@ -39,7 +39,7 @@ func ExtractOutgoing(ctx context.Context) NiceMD { // Clone performs a *deep* copy of the metadata.MD. // -// You can specify the lower-case copiedKeys to only copy certain whitelisted keys. If no keys are explicitly whitelisted +// You can specify the lower-case copiedKeys to only copy certain allow-listed keys. If no keys are explicitly allow-listed // all keys get copied. func (m NiceMD) Clone(copiedKeys ...string) NiceMD { newMd := NiceMD(metadata.Pairs()) @@ -61,7 +61,7 @@ func (m NiceMD) Clone(copiedKeys ...string) NiceMD { newMd[k] = make([]string, len(vv)) copy(newMd[k], vv) } - return NiceMD(newMd) + return newMd } // ToOutgoing sets the given NiceMD as a client-side context for dispatching. diff --git a/vendor/go.uber.org/zap/CHANGELOG.md b/vendor/go.uber.org/zap/CHANGELOG.md index 3b99bf0ac..6c3210121 100644 --- a/vendor/go.uber.org/zap/CHANGELOG.md +++ b/vendor/go.uber.org/zap/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## 1.18.1 (28 Jun 2021) + +Bugfixes: +* [#974][]: Fix nil dereference in logger constructed by `zap.NewNop`. + +[#974]: https://github.com/uber-go/zap/pull/974 + +## 1.18.0 (28 Jun 2021) + +Enhancements: +* [#961][]: Add `zapcore.BufferedWriteSyncer`, a new `WriteSyncer` that buffers + messages in-memory and flushes them periodically. +* [#971][]: Add `zapio.Writer` to use a Zap logger as an `io.Writer`. +* [#897][]: Add `zap.WithClock` option to control the source of time via the + new `zapcore.Clock` interface. +* [#949][]: Avoid panicking in `zap.SugaredLogger` when arguments of `*w` + methods don't match expectations. +* [#943][]: Add support for filtering by level or arbitrary matcher function to + `zaptest/observer`. +* [#691][]: Comply with `io.StringWriter` and `io.ByteWriter` in Zap's + `buffer.Buffer`. + +Thanks to @atrn0, @ernado, @heyanfu, @hnlq715, @zchee +for their contributions to this release. + +[#691]: https://github.com/uber-go/zap/pull/691 +[#897]: https://github.com/uber-go/zap/pull/897 +[#943]: https://github.com/uber-go/zap/pull/943 +[#949]: https://github.com/uber-go/zap/pull/949 +[#961]: https://github.com/uber-go/zap/pull/961 +[#971]: https://github.com/uber-go/zap/pull/971 + ## 1.17.0 (25 May 2021) Bugfixes: diff --git a/vendor/go.uber.org/zap/buffer/buffer.go b/vendor/go.uber.org/zap/buffer/buffer.go index 3f4b86e08..9e929cd98 100644 --- a/vendor/go.uber.org/zap/buffer/buffer.go +++ b/vendor/go.uber.org/zap/buffer/buffer.go @@ -106,6 +106,24 @@ func (b *Buffer) Write(bs []byte) (int, error) { return len(bs), nil } +// WriteByte writes a single byte to the Buffer. +// +// Error returned is always nil, function signature is compatible +// with bytes.Buffer and bufio.Writer +func (b *Buffer) WriteByte(v byte) error { + b.AppendByte(v) + return nil +} + +// WriteString writes a string to the Buffer. +// +// Error returned is always nil, function signature is compatible +// with bytes.Buffer and bufio.Writer +func (b *Buffer) WriteString(s string) (int, error) { + b.AppendString(s) + return len(s), nil +} + // TrimNewline trims any final "\n" byte from the end of the buffer. func (b *Buffer) TrimNewline() { if i := len(b.bs) - 1; i >= 0 { diff --git a/vendor/go.uber.org/zap/logger.go b/vendor/go.uber.org/zap/logger.go index 553f258e7..f116bd936 100644 --- a/vendor/go.uber.org/zap/logger.go +++ b/vendor/go.uber.org/zap/logger.go @@ -26,7 +26,6 @@ import ( "os" "runtime" "strings" - "time" "go.uber.org/zap/zapcore" ) @@ -51,6 +50,8 @@ type Logger struct { addStack zapcore.LevelEnabler callerSkip int + + clock zapcore.Clock } // New constructs a new Logger from the provided zapcore.Core and Options. If @@ -71,6 +72,7 @@ func New(core zapcore.Core, options ...Option) *Logger { core: core, errorOutput: zapcore.Lock(os.Stderr), addStack: zapcore.FatalLevel + 1, + clock: zapcore.DefaultClock, } return log.WithOptions(options...) } @@ -85,6 +87,7 @@ func NewNop() *Logger { core: zapcore.NewNopCore(), errorOutput: zapcore.AddSync(ioutil.Discard), addStack: zapcore.FatalLevel + 1, + clock: zapcore.DefaultClock, } } @@ -270,7 +273,7 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { // log message will actually be written somewhere. ent := zapcore.Entry{ LoggerName: log.name, - Time: time.Now(), + Time: log.clock.Now(), Level: lvl, Message: msg, } @@ -307,7 +310,7 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { if log.addCaller { frame, defined := getCallerFrame(log.callerSkip + callerSkipOffset) if !defined { - fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC()) + fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", ent.Time.UTC()) log.errorOutput.Sync() } diff --git a/vendor/go.uber.org/zap/options.go b/vendor/go.uber.org/zap/options.go index 0135c2092..e9e66161f 100644 --- a/vendor/go.uber.org/zap/options.go +++ b/vendor/go.uber.org/zap/options.go @@ -138,3 +138,11 @@ func OnFatal(action zapcore.CheckWriteAction) Option { log.onFatal = action }) } + +// WithClock specifies the clock used by the logger to determine the current +// time for logged entries. Defaults to the system clock with time.Now. +func WithClock(clock zapcore.Clock) Option { + return optionFunc(func(log *Logger) { + log.clock = clock + }) +} diff --git a/vendor/go.uber.org/zap/sugar.go b/vendor/go.uber.org/zap/sugar.go index 4084dada7..0b9651981 100644 --- a/vendor/go.uber.org/zap/sugar.go +++ b/vendor/go.uber.org/zap/sugar.go @@ -266,7 +266,7 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { // Make sure this element isn't a dangling key. if i == len(args)-1 { - s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i])) + s.base.Error(_oddNumberErrMsg, Any("ignored", args[i])) break } @@ -287,7 +287,7 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { // If we encountered any invalid key-value pairs, log an error. if len(invalid) > 0 { - s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid)) + s.base.Error(_nonStringKeyErrMsg, Array("invalid", invalid)) } return fields } diff --git a/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go b/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go new file mode 100644 index 000000000..0c1436f76 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go @@ -0,0 +1,188 @@ +// Copyright (c) 2021 Uber Technologies, Inc. +// +// 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. + +package zapcore + +import ( + "bufio" + "sync" + "time" + + "go.uber.org/multierr" +) + +const ( + // _defaultBufferSize specifies the default size used by Buffer. + _defaultBufferSize = 256 * 1024 // 256 kB + + // _defaultFlushInterval specifies the default flush interval for + // Buffer. + _defaultFlushInterval = 30 * time.Second +) + +// A BufferedWriteSyncer is a WriteSyncer that buffers writes in-memory before +// flushing them to a wrapped WriteSyncer after reaching some limit, or at some +// fixed interval--whichever comes first. +// +// BufferedWriteSyncer is safe for concurrent use. You don't need to use +// zapcore.Lock for WriteSyncers with BufferedWriteSyncer. +type BufferedWriteSyncer struct { + // WS is the WriteSyncer around which BufferedWriteSyncer will buffer + // writes. + // + // This field is required. + WS WriteSyncer + + // Size specifies the maximum amount of data the writer will buffered + // before flushing. + // + // Defaults to 256 kB if unspecified. + Size int + + // FlushInterval specifies how often the writer should flush data if + // there have been no writes. + // + // Defaults to 30 seconds if unspecified. + FlushInterval time.Duration + + // Clock, if specified, provides control of the source of time for the + // writer. + // + // Defaults to the system clock. + Clock Clock + + // unexported fields for state + mu sync.Mutex + initialized bool // whether initialize() has run + writer *bufio.Writer + ticker *time.Ticker + stop chan struct{} // closed when flushLoop should stop + stopped bool // whether Stop() has run + done chan struct{} // closed when flushLoop has stopped +} + +func (s *BufferedWriteSyncer) initialize() { + size := s.Size + if size == 0 { + size = _defaultBufferSize + } + + flushInterval := s.FlushInterval + if flushInterval == 0 { + flushInterval = _defaultFlushInterval + } + + if s.Clock == nil { + s.Clock = DefaultClock + } + + s.ticker = s.Clock.NewTicker(flushInterval) + s.writer = bufio.NewWriterSize(s.WS, size) + s.stop = make(chan struct{}) + s.done = make(chan struct{}) + s.initialized = true + go s.flushLoop() +} + +// Write writes log data into buffer syncer directly, multiple Write calls will be batched, +// and log data will be flushed to disk when the buffer is full or periodically. +func (s *BufferedWriteSyncer) Write(bs []byte) (int, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if !s.initialized { + s.initialize() + } + + // To avoid partial writes from being flushed, we manually flush the existing buffer if: + // * The current write doesn't fit into the buffer fully, and + // * The buffer is not empty (since bufio will not split large writes when the buffer is empty) + if len(bs) > s.writer.Available() && s.writer.Buffered() > 0 { + if err := s.writer.Flush(); err != nil { + return 0, err + } + } + + return s.writer.Write(bs) +} + +// Sync flushes buffered log data into disk directly. +func (s *BufferedWriteSyncer) Sync() error { + s.mu.Lock() + defer s.mu.Unlock() + + var err error + if s.initialized { + err = s.writer.Flush() + } + + return multierr.Append(err, s.WS.Sync()) +} + +// flushLoop flushes the buffer at the configured interval until Stop is +// called. +func (s *BufferedWriteSyncer) flushLoop() { + defer close(s.done) + + for { + select { + case <-s.ticker.C: + // we just simply ignore error here + // because the underlying bufio writer stores any errors + // and we return any error from Sync() as part of the close + _ = s.Sync() + case <-s.stop: + return + } + } +} + +// Stop closes the buffer, cleans up background goroutines, and flushes +// remaining unwritten data. +func (s *BufferedWriteSyncer) Stop() (err error) { + var stopped bool + + // Critical section. + func() { + s.mu.Lock() + defer s.mu.Unlock() + + if !s.initialized { + return + } + + stopped = s.stopped + if stopped { + return + } + s.stopped = true + + s.ticker.Stop() + close(s.stop) // tell flushLoop to stop + <-s.done // and wait until it has + }() + + // Don't call Sync on consecutive Stops. + if !stopped { + err = s.Sync() + } + + return err +} diff --git a/vendor/go.uber.org/zap/zapcore/clock.go b/vendor/go.uber.org/zap/zapcore/clock.go new file mode 100644 index 000000000..d2ea95b39 --- /dev/null +++ b/vendor/go.uber.org/zap/zapcore/clock.go @@ -0,0 +1,50 @@ +// Copyright (c) 2021 Uber Technologies, Inc. +// +// 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. + +package zapcore + +import ( + "time" +) + +// DefaultClock is the default clock used by Zap in operations that require +// time. This clock uses the system clock for all operations. +var DefaultClock = systemClock{} + +// Clock is a source of time for logged entries. +type Clock interface { + // Now returns the current local time. + Now() time.Time + + // NewTicker returns *time.Ticker that holds a channel + // that delivers "ticks" of a clock. + NewTicker(time.Duration) *time.Ticker +} + +// systemClock implements default Clock that uses system time. +type systemClock struct{} + +func (systemClock) Now() time.Time { + return time.Now() +} + +func (systemClock) NewTicker(duration time.Duration) *time.Ticker { + return time.NewTicker(duration) +} diff --git a/vendor/go.uber.org/zap/zapcore/entry.go b/vendor/go.uber.org/zap/zapcore/entry.go index 4aa8b4f90..2d815feb8 100644 --- a/vendor/go.uber.org/zap/zapcore/entry.go +++ b/vendor/go.uber.org/zap/zapcore/entry.go @@ -208,7 +208,7 @@ func (ce *CheckedEntry) Write(fields ...Field) { // If the entry is dirty, log an internal error; because the // CheckedEntry is being used after it was returned to the pool, // the message may be an amalgamation from multiple call sites. - fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", time.Now(), ce.Entry) + fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", ce.Time, ce.Entry) ce.ErrorOutput.Sync() } return @@ -221,7 +221,7 @@ func (ce *CheckedEntry) Write(fields ...Field) { } if ce.ErrorOutput != nil { if err != nil { - fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", time.Now(), err) + fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", ce.Time, err) ce.ErrorOutput.Sync() } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 77fff565c..ae6ce1069 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -320,7 +320,7 @@ github.com/gostaticanalysis/forcetypeassert # github.com/gostaticanalysis/nilerr v0.1.1 ## explicit; go 1.15 github.com/gostaticanalysis/nilerr -# github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 +# github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 ## explicit; go 1.14 github.com/grpc-ecosystem/go-grpc-middleware github.com/grpc-ecosystem/go-grpc-middleware/auth @@ -782,7 +782,7 @@ go.uber.org/atomic # go.uber.org/multierr v1.6.0 ## explicit; go 1.12 go.uber.org/multierr -# go.uber.org/zap v1.17.0 +# go.uber.org/zap v1.18.1 ## explicit; go 1.13 go.uber.org/zap go.uber.org/zap/buffer From 15e7cc8663c72c01a61efc5a1dafdf8ce9bf0349 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:21:39 +0200 Subject: [PATCH 13/31] gomod: Add github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus --- go.mod | 11 +- go.sum | 30 +- .../providers/prometheus}/LICENSE | 0 .../providers/prometheus/client_metrics.go | 117 + .../providers/prometheus/client_options.go | 77 + .../providers/prometheus/constants.go | 23 + .../providers/prometheus/doc.go | 8 + .../providers/prometheus/options.go | 129 + .../providers/prometheus/reporter.go | 113 + .../providers/prometheus/server_metrics.go | 123 + .../providers/prometheus/server_options.go | 48 + .../go-grpc-middleware/v2/COPYRIGHT | 2 + .../go-grpc-middleware/v2/LICENSE | 201 + .../v2/interceptors/client.go | 83 + .../go-grpc-middleware/v2/interceptors/doc.go | 12 + .../v2/interceptors/reporter.go | 116 + .../v2/interceptors/server.go | 74 + .../go-grpc-prometheus/.gitignore | 201 - .../go-grpc-prometheus/.travis.yml | 25 - .../go-grpc-prometheus/CHANGELOG.md | 24 - .../go-grpc-prometheus/README.md | 247 - .../go-grpc-prometheus/client.go | 39 - .../go-grpc-prometheus/client_metrics.go | 170 - .../go-grpc-prometheus/client_reporter.go | 46 - .../go-grpc-prometheus/makefile | 16 - .../go-grpc-prometheus/metric_options.go | 41 - .../go-grpc-prometheus/server.go | 48 - .../go-grpc-prometheus/server_metrics.go | 185 - .../go-grpc-prometheus/server_reporter.go | 46 - .../grpc-ecosystem/go-grpc-prometheus/util.go | 50 - .../client_golang/prometheus/collector.go | 6 +- .../client_golang/prometheus/counter.go | 13 +- .../client_golang/prometheus/desc.go | 5 +- .../client_golang/prometheus/doc.go | 107 +- .../client_golang/prometheus/gauge.go | 6 +- .../client_golang/prometheus/get_pid.go | 26 + .../prometheus/get_pid_gopherjs.go | 23 + .../client_golang/prometheus/go_collector.go | 20 +- .../prometheus/go_collector_go116.go | 17 +- ...lector_go117.go => go_collector_latest.go} | 314 +- .../client_golang/prometheus/histogram.go | 980 ++- .../prometheus/internal/almost_equal.go | 60 + .../prometheus/internal/difflib.go | 654 ++ .../internal/go_collector_options.go | 32 + .../prometheus/internal/go_runtime_metrics.go | 18 +- .../prometheus/internal/metric.go | 28 +- .../client_golang/prometheus/labels.go | 9 +- .../client_golang/prometheus/metric.go | 112 +- .../client_golang/prometheus/num_threads.go | 25 + .../prometheus/num_threads_gopherjs.go | 22 + .../client_golang/prometheus/observer.go | 2 +- .../prometheus/process_collector.go | 10 +- .../prometheus/process_collector_js.go | 26 + .../prometheus/process_collector_other.go | 4 +- .../prometheus/promhttp/delegator.go | 18 +- .../client_golang/prometheus/promhttp/http.go | 20 +- .../prometheus/promhttp/instrument_client.go | 40 +- .../prometheus/promhttp/instrument_server.go | 123 +- .../prometheus/promhttp/option.go | 39 +- .../client_golang/prometheus/registry.go | 152 +- .../client_golang/prometheus/summary.go | 9 +- .../prometheus/testutil/promlint/promlint.go | 5 +- .../client_golang/prometheus/timer.go | 11 +- .../client_golang/prometheus/value.go | 47 +- .../client_golang/prometheus/vec.go | 88 +- .../client_golang/prometheus/wrap.go | 4 +- .../prometheus/client_model/go/metrics.pb.go | 333 +- .../prometheus/common/expfmt/fuzz.go | 1 + .../common/expfmt/openmetrics_create.go | 4 +- .../prometheus/common/model/time.go | 2 +- .../github.com/prometheus/procfs/.gitignore | 3 +- .../prometheus/procfs/.golangci.yml | 10 +- .../prometheus/procfs/CODE_OF_CONDUCT.md | 4 +- .../prometheus/procfs/CONTRIBUTING.md | 4 +- vendor/github.com/prometheus/procfs/Makefile | 10 +- .../prometheus/procfs/Makefile.common | 89 +- .../github.com/prometheus/procfs/SECURITY.md | 2 +- vendor/github.com/prometheus/procfs/arp.go | 45 +- .../github.com/prometheus/procfs/cpuinfo.go | 5 +- .../prometheus/procfs/cpuinfo_armx.go | 1 + .../prometheus/procfs/cpuinfo_mipsx.go | 1 + .../prometheus/procfs/cpuinfo_others.go | 4 +- .../prometheus/procfs/cpuinfo_ppcx.go | 1 + .../prometheus/procfs/cpuinfo_riscvx.go | 1 + .../prometheus/procfs/cpuinfo_s390x.go | 1 + .../prometheus/procfs/cpuinfo_x86.go | 1 + .../prometheus/procfs/fixtures.ttar | 7673 ----------------- .../prometheus/procfs/internal/fs/fs.go | 2 +- .../prometheus/procfs/internal/util/parse.go | 6 +- .../procfs/internal/util/readfile.go | 11 +- .../procfs/internal/util/sysreadfile.go | 8 +- .../internal/util/sysreadfile_compat.go | 3 +- vendor/github.com/prometheus/procfs/ipvs.go | 3 +- .../prometheus/procfs/kernel_random.go | 1 + .../github.com/prometheus/procfs/loadavg.go | 2 +- vendor/github.com/prometheus/procfs/mdstat.go | 10 +- .../prometheus/procfs/net_conntrackstat.go | 12 +- .../github.com/prometheus/procfs/net_dev.go | 8 +- .../prometheus/procfs/net_ip_socket.go | 2 +- .../prometheus/procfs/net_protocols.go | 4 +- .../prometheus/procfs/net_softnet.go | 8 +- .../procfs/{xfrm.go => net_xfrm.go} | 9 +- .../github.com/prometheus/procfs/netstat.go | 8 +- vendor/github.com/prometheus/procfs/proc.go | 10 +- .../prometheus/procfs/proc_cgroup.go | 6 +- .../prometheus/procfs/proc_cgroups.go | 98 + .../prometheus/procfs/proc_environ.go | 2 +- .../prometheus/procfs/proc_fdinfo.go | 3 +- .../prometheus/procfs/proc_limits.go | 2 +- .../github.com/prometheus/procfs/proc_maps.go | 12 +- .../prometheus/procfs/proc_netstat.go | 440 + .../github.com/prometheus/procfs/proc_psi.go | 14 +- .../prometheus/procfs/proc_smaps.go | 23 +- .../github.com/prometheus/procfs/proc_snmp.go | 353 + .../prometheus/procfs/proc_snmp6.go | 381 + .../github.com/prometheus/procfs/proc_stat.go | 11 +- .../prometheus/procfs/proc_status.go | 32 +- .../github.com/prometheus/procfs/proc_sys.go | 51 + .../github.com/prometheus/procfs/schedstat.go | 6 +- vendor/github.com/prometheus/procfs/slab.go | 2 +- .../github.com/prometheus/procfs/softirqs.go | 160 + vendor/github.com/prometheus/procfs/stat.go | 10 +- vendor/github.com/prometheus/procfs/vm.go | 6 +- .../github.com/prometheus/procfs/zoneinfo.go | 5 +- vendor/golang.org/x/net/context/context.go | 56 - vendor/golang.org/x/net/context/go17.go | 73 - vendor/golang.org/x/net/context/go19.go | 21 - vendor/golang.org/x/net/context/pre_go17.go | 301 - vendor/golang.org/x/net/context/pre_go19.go | 110 - vendor/modules.txt | 24 +- 130 files changed, 5835 insertions(+), 10049 deletions(-) rename vendor/github.com/grpc-ecosystem/{go-grpc-prometheus => go-grpc-middleware/providers/prometheus}/LICENSE (100%) create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_metrics.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_options.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/constants.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/doc.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/options.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/reporter.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_metrics.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_options.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/COPYRIGHT create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/LICENSE create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go create mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.gitignore delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.travis.yml delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/CHANGELOG.md delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/README.md delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_metrics.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_reporter.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/makefile delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/metric_options.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_metrics.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_reporter.go delete mode 100644 vendor/github.com/grpc-ecosystem/go-grpc-prometheus/util.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/get_pid.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go rename vendor/github.com/prometheus/client_golang/prometheus/{go_collector_go117.go => go_collector_latest.go} (53%) create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/num_threads.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/process_collector_js.go delete mode 100644 vendor/github.com/prometheus/procfs/fixtures.ttar rename vendor/github.com/prometheus/procfs/{xfrm.go => net_xfrm.go} (96%) create mode 100644 vendor/github.com/prometheus/procfs/proc_cgroups.go create mode 100644 vendor/github.com/prometheus/procfs/proc_netstat.go create mode 100644 vendor/github.com/prometheus/procfs/proc_snmp.go create mode 100644 vendor/github.com/prometheus/procfs/proc_snmp6.go create mode 100644 vendor/github.com/prometheus/procfs/proc_sys.go create mode 100644 vendor/github.com/prometheus/procfs/softirqs.go delete mode 100644 vendor/golang.org/x/net/context/context.go delete mode 100644 vendor/golang.org/x/net/context/go17.go delete mode 100644 vendor/golang.org/x/net/context/go19.go delete mode 100644 vendor/golang.org/x/net/context/pre_go17.go delete mode 100644 vendor/golang.org/x/net/context/pre_go19.go diff --git a/go.mod b/go.mod index 3969aa586..706ce7b99 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 github.com/jpillora/backoff v1.0.0 github.com/mattn/go-isatty v0.0.17 github.com/mattn/goveralls v0.0.9 @@ -30,7 +30,7 @@ require ( github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 - github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/client_golang v1.14.0 github.com/rs/xid v1.2.1 github.com/rs/zerolog v1.17.2 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 @@ -113,6 +113,7 @@ require ( github.com/gostaticanalysis/comment v1.4.2 // indirect github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect @@ -162,9 +163,9 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/polyfloyd/go-errorlint v1.1.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/quasilyte/go-ruleguard v0.3.19 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect diff --git a/go.sum b/go.sum index cdede208c..e510bbbb9 100644 --- a/go.sum +++ b/go.sum @@ -146,6 +146,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= @@ -179,6 +180,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 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-kivik/couchdb/v3 v3.2.6 h1:IzoAH5K7jsY1BFNibtdjAoPXRmm3rdQKJGjDMzXMvok= github.com/go-kivik/couchdb/v3 v3.2.6/go.mod h1:tUgf+ftTYkkNPyHskJW2O+6I1NUQvg7ucooVvhPQcxg= github.com/go-kivik/kivik/v3 v3.0.1/go.mod h1:7tmQDvkta/pcijpUjLMsQ9HJUELiKD5zm6jQ3Gb9cxE= @@ -190,6 +192,7 @@ github.com/go-kivik/kiviktest/v3 v3.0.3/go.mod h1:sqsz3M2sJxTxAUdOj+2SU21y4phcpY 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-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-pg/pg v6.14.5+incompatible h1:Tc74MTCCIVd8sAJshYHqutcHhO64/EBHBTydzCGt3Js= @@ -342,8 +345,10 @@ github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoIS github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 h1:f4tggROQKKcnh4eItay6z/HbHLqghBxS8g7pyMhmDio= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0/go.mod h1:hKAkSgNkL0FII46ZkJcpVEAai4KV+swlIWCKfekd1pA= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 h1:o95KDiV/b1xdkumY5YbLR0/n2+wBxUpgf3HgfKgTyLI= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3/go.mod h1:hTxjzRcX49ogbTGVJ1sM5mz5s+SSgiGIyL3jjPxl32E= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -528,24 +533,28 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP 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 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= 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/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 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 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= 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 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= 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/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc= github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= @@ -795,9 +804,12 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/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/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -814,7 +826,9 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -885,6 +899,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1068,6 +1083,7 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY 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-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1094,10 +1110,12 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/LICENSE b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/LICENSE similarity index 100% rename from vendor/github.com/grpc-ecosystem/go-grpc-prometheus/LICENSE rename to vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/LICENSE diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_metrics.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_metrics.go new file mode 100644 index 000000000..5c8ba2076 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_metrics.go @@ -0,0 +1,117 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +import ( + "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors" + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc" +) + +// ClientMetrics represents a collection of metrics to be registered on a +// Prometheus metrics registry for a gRPC client. +type ClientMetrics struct { + clientStartedCounter *prometheus.CounterVec + clientHandledCounter *prometheus.CounterVec + clientStreamMsgReceived *prometheus.CounterVec + clientStreamMsgSent *prometheus.CounterVec + + // clientHandledHistogram can be nil + clientHandledHistogram *prometheus.HistogramVec + // clientStreamRecvHistogram can be nil + clientStreamRecvHistogram *prometheus.HistogramVec + // clientStreamSendHistogram can be nil + clientStreamSendHistogram *prometheus.HistogramVec +} + +// NewClientMetrics returns a new ClientMetrics object. +// NOTE: Remember to register ClientMetrics object using prometheus registry +// e.g. prometheus.MustRegister(myClientMetrics). +func NewClientMetrics(opts ...ClientMetricsOption) *ClientMetrics { + var config clientMetricsConfig + config.apply(opts) + return &ClientMetrics{ + clientStartedCounter: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_client_started_total", + Help: "Total number of RPCs started on the client.", + }), []string{"grpc_type", "grpc_service", "grpc_method"}), + + clientHandledCounter: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_client_handled_total", + Help: "Total number of RPCs completed by the client, regardless of success or failure.", + }), []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"}), + + clientStreamMsgReceived: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_client_msg_received_total", + Help: "Total number of RPC stream messages received by the client.", + }), []string{"grpc_type", "grpc_service", "grpc_method"}), + + clientStreamMsgSent: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_client_msg_sent_total", + Help: "Total number of gRPC stream messages sent by the client.", + }), []string{"grpc_type", "grpc_service", "grpc_method"}), + + clientHandledHistogram: config.clientHandledHistogram, + clientStreamRecvHistogram: config.clientStreamRecvHistogram, + clientStreamSendHistogram: config.clientStreamSendHistogram, + } +} + +// 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. +func (m *ClientMetrics) Describe(ch chan<- *prometheus.Desc) { + m.clientStartedCounter.Describe(ch) + m.clientHandledCounter.Describe(ch) + m.clientStreamMsgReceived.Describe(ch) + m.clientStreamMsgSent.Describe(ch) + if m.clientHandledHistogram != nil { + m.clientHandledHistogram.Describe(ch) + } + if m.clientStreamRecvHistogram != nil { + m.clientStreamRecvHistogram.Describe(ch) + } + if m.clientStreamSendHistogram != nil { + m.clientStreamSendHistogram.Describe(ch) + } +} + +// 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. +func (m *ClientMetrics) Collect(ch chan<- prometheus.Metric) { + m.clientStartedCounter.Collect(ch) + m.clientHandledCounter.Collect(ch) + m.clientStreamMsgReceived.Collect(ch) + m.clientStreamMsgSent.Collect(ch) + if m.clientHandledHistogram != nil { + m.clientHandledHistogram.Collect(ch) + } + if m.clientStreamRecvHistogram != nil { + m.clientStreamRecvHistogram.Collect(ch) + } + if m.clientStreamSendHistogram != nil { + m.clientStreamSendHistogram.Collect(ch) + } +} + +// UnaryClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Unary RPCs. +func (m *ClientMetrics) UnaryClientInterceptor(opts ...Option) grpc.UnaryClientInterceptor { + return interceptors.UnaryClientInterceptor(&reportable{ + opts: opts, + clientMetrics: m, + }) +} + +// StreamClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Streaming RPCs. +func (m *ClientMetrics) StreamClientInterceptor(opts ...Option) grpc.StreamClientInterceptor { + return interceptors.StreamClientInterceptor(&reportable{ + opts: opts, + clientMetrics: m, + }) +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_options.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_options.go new file mode 100644 index 000000000..c2671679c --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/client_options.go @@ -0,0 +1,77 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +type clientMetricsConfig struct { + counterOpts counterOptions + // clientHandledHistogram can be nil. + clientHandledHistogram *prometheus.HistogramVec + // clientStreamRecvHistogram can be nil. + clientStreamRecvHistogram *prometheus.HistogramVec + // clientStreamSendHistogram can be nil. + clientStreamSendHistogram *prometheus.HistogramVec +} + +type ClientMetricsOption func(*clientMetricsConfig) + +func (c *clientMetricsConfig) apply(opts []ClientMetricsOption) { + for _, o := range opts { + o(c) + } +} + +func WithClientCounterOptions(opts ...CounterOption) ClientMetricsOption { + return func(o *clientMetricsConfig) { + o.counterOpts = opts + } +} + +// WithClientHandlingTimeHistogram turns on recording of handling time of RPCs. +// Histogram metrics can be very expensive for Prometheus to retain and query. +func WithClientHandlingTimeHistogram(opts ...HistogramOption) ClientMetricsOption { + return func(o *clientMetricsConfig) { + o.clientHandledHistogram = prometheus.NewHistogramVec( + histogramOptions(opts).apply(prometheus.HistogramOpts{ + Name: "grpc_client_handling_seconds", + Help: "Histogram of response latency (seconds) of the gRPC until it is finished by the application.", + Buckets: prometheus.DefBuckets, + }), + []string{"grpc_type", "grpc_service", "grpc_method"}, + ) + } +} + +// WithClientStreamRecvHistogram turns on recording of single message receive time of streaming RPCs. +// Histogram metrics can be very expensive for Prometheus to retain and query. +func WithClientStreamRecvHistogram(opts ...HistogramOption) ClientMetricsOption { + return func(o *clientMetricsConfig) { + o.clientStreamRecvHistogram = prometheus.NewHistogramVec( + histogramOptions(opts).apply(prometheus.HistogramOpts{ + Name: "grpc_client_msg_recv_handling_seconds", + Help: "Histogram of response latency (seconds) of the gRPC single message receive.", + Buckets: prometheus.DefBuckets, + }), + []string{"grpc_type", "grpc_service", "grpc_method"}, + ) + } +} + +// WithClientStreamSendHistogram turns on recording of single message send time of streaming RPCs. +// Histogram metrics can be very expensive for Prometheus to retain and query. +func WithClientStreamSendHistogram(opts ...HistogramOption) ClientMetricsOption { + return func(o *clientMetricsConfig) { + o.clientStreamSendHistogram = prometheus.NewHistogramVec( + histogramOptions(opts).apply(prometheus.HistogramOpts{ + Name: "grpc_client_msg_send_handling_seconds", + Help: "Histogram of response latency (seconds) of the gRPC single message send.", + Buckets: prometheus.DefBuckets, + }), + []string{"grpc_type", "grpc_service", "grpc_method"}, + ) + } +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/constants.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/constants.go new file mode 100644 index 000000000..5c36923f7 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/constants.go @@ -0,0 +1,23 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +type grpcType string + +// grpcType describes all types of grpc connection. +const ( + Unary grpcType = "unary" + ClientStream grpcType = "client_stream" + ServerStream grpcType = "server_stream" + BidiStream grpcType = "bidi_stream" +) + +// Kind describes whether interceptor is a client or server type. +type Kind string + +// Enum for Client and Server Kind. +const ( + KindClient Kind = "client" + KindServer Kind = "server" +) diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/doc.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/doc.go new file mode 100644 index 000000000..b62f17efb --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/doc.go @@ -0,0 +1,8 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +/* +Package prometheus provides a standalone interceptor for metrics. It's next iteration of deprecated https://github.com/grpc-ecosystem/go-grpc-prometheus. +See https://github.com/grpc-ecosystem/go-grpc-middleware/tree/main/examples for example. +*/ +package prometheus diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/options.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/options.go new file mode 100644 index 000000000..bdd171e29 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/options.go @@ -0,0 +1,129 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +import ( + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc" + "google.golang.org/grpc/status" +) + +// FromError returns a grpc status. If the error code is neither a valid grpc status nor a context error, codes.Unknown +// will be set. +func FromError(err error) *status.Status { + s, ok := status.FromError(err) + // Mirror what the grpc server itself does, i.e. also convert context errors to status + if !ok { + s = status.FromContextError(err) + } + return s +} + +// A CounterOption lets you add options to Counter metrics using With* funcs. +type CounterOption func(*prometheus.CounterOpts) + +type counterOptions []CounterOption + +func (co counterOptions) apply(o prometheus.CounterOpts) prometheus.CounterOpts { + for _, f := range co { + f(&o) + } + return o +} + +// WithConstLabels allows you to add ConstLabels to Counter metrics. +func WithConstLabels(labels prometheus.Labels) CounterOption { + return func(o *prometheus.CounterOpts) { + o.ConstLabels = labels + } +} + +// WithSubsystem allows you to add a Subsystem to Counter metrics. +func WithSubsystem(subsystem string) CounterOption { + return func(o *prometheus.CounterOpts) { + o.Subsystem = subsystem + } +} + +// A HistogramOption lets you add options to Histogram metrics using With* +// funcs. +type HistogramOption func(*prometheus.HistogramOpts) + +type histogramOptions []HistogramOption + +func (ho histogramOptions) apply(o prometheus.HistogramOpts) prometheus.HistogramOpts { + for _, f := range ho { + f(&o) + } + return o +} + +// WithHistogramBuckets allows you to specify custom bucket ranges for histograms if EnableHandlingTimeHistogram is on. +func WithHistogramBuckets(buckets []float64) HistogramOption { + return func(o *prometheus.HistogramOpts) { o.Buckets = buckets } +} + +// WithHistogramOpts allows you to specify HistogramOpts but makes sure the correct name and label is used. +// This function is helpful when specifying more than just the buckets, like using NativeHistograms. +func WithHistogramOpts(opts *prometheus.HistogramOpts) HistogramOption { + // TODO: This isn't ideal either if new fields are added to prometheus.HistogramOpts. + // Maybe we can change the interface to accept abitrary HistogramOpts and + // only make sure to overwrite the necessary fields (name, labels). + return func(o *prometheus.HistogramOpts) { + o.Buckets = opts.Buckets + o.NativeHistogramBucketFactor = opts.NativeHistogramBucketFactor + o.NativeHistogramZeroThreshold = opts.NativeHistogramZeroThreshold + o.NativeHistogramMaxBucketNumber = opts.NativeHistogramMaxBucketNumber + o.NativeHistogramMinResetDuration = opts.NativeHistogramMinResetDuration + o.NativeHistogramMaxZeroThreshold = opts.NativeHistogramMaxZeroThreshold + } +} + +// WithHistogramConstLabels allows you to add custom ConstLabels to +// histograms metrics. +func WithHistogramConstLabels(labels prometheus.Labels) HistogramOption { + return func(o *prometheus.HistogramOpts) { + o.ConstLabels = labels + } +} + +// WithHistogramSubsystem allows you to add a Subsystem to histograms metrics. +func WithHistogramSubsystem(subsystem string) HistogramOption { + return func(o *prometheus.HistogramOpts) { + o.Subsystem = subsystem + } +} + +func typeFromMethodInfo(mInfo *grpc.MethodInfo) grpcType { + if !mInfo.IsClientStream && !mInfo.IsServerStream { + return Unary + } + if mInfo.IsClientStream && !mInfo.IsServerStream { + return ClientStream + } + if !mInfo.IsClientStream && mInfo.IsServerStream { + return ServerStream + } + return BidiStream +} + +// An Option lets you add options to prometheus interceptors using With* funcs. +type Option func(*config) + +type config struct { + exemplarFn exemplarFromCtxFn +} + +func (c *config) apply(opts []Option) { + for _, o := range opts { + o(c) + } +} + +// WithExemplarFromContext sets function that will be used to deduce exemplar for all counter and histogram metrics. +func WithExemplarFromContext(exemplarFn exemplarFromCtxFn) Option { + return func(o *config) { + o.exemplarFn = exemplarFn + } +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/reporter.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/reporter.go new file mode 100644 index 000000000..96c49ad93 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/reporter.go @@ -0,0 +1,113 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +import ( + "context" + "time" + + "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors" + "github.com/prometheus/client_golang/prometheus" +) + +type reporter struct { + clientMetrics *ClientMetrics + serverMetrics *ServerMetrics + typ interceptors.GRPCType + service, method string + kind Kind + exemplar prometheus.Labels +} + +func (r *reporter) PostCall(err error, rpcDuration time.Duration) { + // get status code from error + status := FromError(err) + code := status.Code() + + // perform handling of metrics from code + switch r.kind { + case KindServer: + r.incrementWithExemplar(r.serverMetrics.serverHandledCounter, string(r.typ), r.service, r.method, code.String()) + if r.serverMetrics.serverHandledHistogram != nil { + r.observeWithExemplar(r.serverMetrics.serverHandledHistogram, rpcDuration.Seconds(), string(r.typ), r.service, r.method) + } + + case KindClient: + r.incrementWithExemplar(r.clientMetrics.clientHandledCounter, string(r.typ), r.service, r.method, code.String()) + if r.clientMetrics.clientHandledHistogram != nil { + r.observeWithExemplar(r.clientMetrics.clientHandledHistogram, rpcDuration.Seconds(), string(r.typ), r.service, r.method) + } + } +} + +func (r *reporter) PostMsgSend(_ any, _ error, sendDuration time.Duration) { + switch r.kind { + case KindServer: + r.incrementWithExemplar(r.serverMetrics.serverStreamMsgSent, string(r.typ), r.service, r.method) + case KindClient: + r.incrementWithExemplar(r.clientMetrics.clientStreamMsgSent, string(r.typ), r.service, r.method) + if r.clientMetrics.clientStreamSendHistogram != nil { + r.observeWithExemplar(r.clientMetrics.clientStreamSendHistogram, sendDuration.Seconds(), string(r.typ), r.service, r.method) + } + } +} + +func (r *reporter) PostMsgReceive(_ any, _ error, recvDuration time.Duration) { + switch r.kind { + case KindServer: + r.incrementWithExemplar(r.serverMetrics.serverStreamMsgReceived, string(r.typ), r.service, r.method) + case KindClient: + r.incrementWithExemplar(r.clientMetrics.clientStreamMsgReceived, string(r.typ), r.service, r.method) + if r.clientMetrics.clientStreamRecvHistogram != nil { + r.observeWithExemplar(r.clientMetrics.clientStreamRecvHistogram, recvDuration.Seconds(), string(r.typ), r.service, r.method) + } + } +} + +type reportable struct { + clientMetrics *ClientMetrics + serverMetrics *ServerMetrics + + opts []Option +} + +func (rep *reportable) ServerReporter(ctx context.Context, meta interceptors.CallMeta) (interceptors.Reporter, context.Context) { + return rep.reporter(ctx, rep.serverMetrics, nil, meta, KindServer) +} + +func (rep *reportable) ClientReporter(ctx context.Context, meta interceptors.CallMeta) (interceptors.Reporter, context.Context) { + return rep.reporter(ctx, nil, rep.clientMetrics, meta, KindClient) +} + +func (rep *reportable) reporter(ctx context.Context, sm *ServerMetrics, cm *ClientMetrics, meta interceptors.CallMeta, kind Kind) (interceptors.Reporter, context.Context) { + var c config + c.apply(rep.opts) + r := &reporter{ + clientMetrics: cm, + serverMetrics: sm, + typ: meta.Typ, + service: meta.Service, + method: meta.Method, + kind: kind, + } + if c.exemplarFn != nil { + r.exemplar = c.exemplarFn(ctx) + } + + switch kind { + case KindClient: + r.incrementWithExemplar(r.clientMetrics.clientStartedCounter, string(r.typ), r.service, r.method) + case KindServer: + r.incrementWithExemplar(r.serverMetrics.serverStartedCounter, string(r.typ), r.service, r.method) + } + return r, ctx +} + +func (r *reporter) incrementWithExemplar(c *prometheus.CounterVec, lvals ...string) { + c.WithLabelValues(lvals...).(prometheus.ExemplarAdder).AddWithExemplar(1, r.exemplar) +} + +func (r *reporter) observeWithExemplar(h *prometheus.HistogramVec, value float64, lvals ...string) { + h.WithLabelValues(lvals...).(prometheus.ExemplarObserver).ObserveWithExemplar(value, r.exemplar) +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_metrics.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_metrics.go new file mode 100644 index 000000000..9b2f3e6d8 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_metrics.go @@ -0,0 +1,123 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +import ( + "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors" + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/grpc" +) + +// ServerMetrics represents a collection of metrics to be registered on a +// Prometheus metrics registry for a gRPC server. +type ServerMetrics struct { + serverStartedCounter *prometheus.CounterVec + serverHandledCounter *prometheus.CounterVec + serverStreamMsgReceived *prometheus.CounterVec + serverStreamMsgSent *prometheus.CounterVec + // serverHandledHistogram can be nil. + serverHandledHistogram *prometheus.HistogramVec +} + +// NewServerMetrics returns a new ServerMetrics object that has server interceptor methods. +// NOTE: Remember to register ServerMetrics object by using prometheus registry +// e.g. prometheus.MustRegister(myServerMetrics). +func NewServerMetrics(opts ...ServerMetricsOption) *ServerMetrics { + var config serverMetricsConfig + config.apply(opts) + return &ServerMetrics{ + serverStartedCounter: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_server_started_total", + Help: "Total number of RPCs started on the server.", + }), []string{"grpc_type", "grpc_service", "grpc_method"}), + serverHandledCounter: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_server_handled_total", + Help: "Total number of RPCs completed on the server, regardless of success or failure.", + }), []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"}), + serverStreamMsgReceived: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_server_msg_received_total", + Help: "Total number of RPC stream messages received on the server.", + }), []string{"grpc_type", "grpc_service", "grpc_method"}), + serverStreamMsgSent: prometheus.NewCounterVec( + config.counterOpts.apply(prometheus.CounterOpts{ + Name: "grpc_server_msg_sent_total", + Help: "Total number of gRPC stream messages sent by the server.", + }), []string{"grpc_type", "grpc_service", "grpc_method"}), + serverHandledHistogram: config.serverHandledHistogram, + } +} + +// 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. +func (m *ServerMetrics) Describe(ch chan<- *prometheus.Desc) { + m.serverStartedCounter.Describe(ch) + m.serverHandledCounter.Describe(ch) + m.serverStreamMsgReceived.Describe(ch) + m.serverStreamMsgSent.Describe(ch) + if m.serverHandledHistogram != nil { + m.serverHandledHistogram.Describe(ch) + } +} + +// 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. +func (m *ServerMetrics) Collect(ch chan<- prometheus.Metric) { + m.serverStartedCounter.Collect(ch) + m.serverHandledCounter.Collect(ch) + m.serverStreamMsgReceived.Collect(ch) + m.serverStreamMsgSent.Collect(ch) + if m.serverHandledHistogram != nil { + m.serverHandledHistogram.Collect(ch) + } +} + +// InitializeMetrics initializes all metrics, with their appropriate null +// value, for all gRPC methods registered on a gRPC server. This is useful, to +// ensure that all metrics exist when collecting and querying. +// NOTE: This might add significant cardinality and might not be needed in future version of Prometheus (created timestamp). +func (m *ServerMetrics) InitializeMetrics(server *grpc.Server) { + serviceInfo := server.GetServiceInfo() + for serviceName, info := range serviceInfo { + for _, mInfo := range info.Methods { + m.preRegisterMethod(serviceName, &mInfo) + } + } +} + +// preRegisterMethod is invoked on Register of a Server, allowing all gRPC services labels to be pre-populated. +func (m *ServerMetrics) preRegisterMethod(serviceName string, mInfo *grpc.MethodInfo) { + methodName := mInfo.Name + methodType := string(typeFromMethodInfo(mInfo)) + // These are just references (no increments), as just referencing will create the labels but not set values. + _, _ = m.serverStartedCounter.GetMetricWithLabelValues(methodType, serviceName, methodName) + _, _ = m.serverStreamMsgReceived.GetMetricWithLabelValues(methodType, serviceName, methodName) + _, _ = m.serverStreamMsgSent.GetMetricWithLabelValues(methodType, serviceName, methodName) + if m.serverHandledHistogram != nil { + _, _ = m.serverHandledHistogram.GetMetricWithLabelValues(methodType, serviceName, methodName) + } + for _, code := range interceptors.AllCodes { + _, _ = m.serverHandledCounter.GetMetricWithLabelValues(methodType, serviceName, methodName, code.String()) + } +} + +// UnaryServerInterceptor is a gRPC server-side interceptor that provides Prometheus monitoring for Unary RPCs. +func (m *ServerMetrics) UnaryServerInterceptor(opts ...Option) grpc.UnaryServerInterceptor { + return interceptors.UnaryServerInterceptor(&reportable{ + opts: opts, + serverMetrics: m, + }) +} + +// StreamServerInterceptor is a gRPC server-side interceptor that provides Prometheus monitoring for Streaming RPCs. +func (m *ServerMetrics) StreamServerInterceptor(opts ...Option) grpc.StreamServerInterceptor { + return interceptors.StreamServerInterceptor(&reportable{ + opts: opts, + serverMetrics: m, + }) +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_options.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_options.go new file mode 100644 index 000000000..39d422042 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus/server_options.go @@ -0,0 +1,48 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package prometheus + +import ( + "context" + + "github.com/prometheus/client_golang/prometheus" +) + +type exemplarFromCtxFn func(ctx context.Context) prometheus.Labels + +type serverMetricsConfig struct { + counterOpts counterOptions + // serverHandledHistogram can be nil. + serverHandledHistogram *prometheus.HistogramVec +} + +type ServerMetricsOption func(*serverMetricsConfig) + +func (c *serverMetricsConfig) apply(opts []ServerMetricsOption) { + for _, o := range opts { + o(c) + } +} + +// WithServerCounterOptions sets counter options. +func WithServerCounterOptions(opts ...CounterOption) ServerMetricsOption { + return func(o *serverMetricsConfig) { + o.counterOpts = opts + } +} + +// WithServerHandlingTimeHistogram turns on recording of handling time of RPCs. +// Histogram metrics can be very expensive for Prometheus to retain and query. +func WithServerHandlingTimeHistogram(opts ...HistogramOption) ServerMetricsOption { + return func(o *serverMetricsConfig) { + o.serverHandledHistogram = prometheus.NewHistogramVec( + histogramOptions(opts).apply(prometheus.HistogramOpts{ + Name: "grpc_server_handling_seconds", + Help: "Histogram of response latency (seconds) of gRPC that had been application-level handled by the server.", + Buckets: prometheus.DefBuckets, + }), + []string{"grpc_type", "grpc_service", "grpc_method"}, + ) + } +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/COPYRIGHT b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/COPYRIGHT new file mode 100644 index 000000000..3b13627cd --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/COPYRIGHT @@ -0,0 +1,2 @@ +Copyright (c) The go-grpc-middleware Authors. +Licensed under the Apache License 2.0. diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/LICENSE b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/LICENSE new file mode 100644 index 000000000..b2b065037 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/LICENSE @@ -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. \ No newline at end of file diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go new file mode 100644 index 000000000..86c51a079 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go @@ -0,0 +1,83 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +// Go gRPC Middleware monitoring interceptors for client-side gRPC. + +package interceptors + +import ( + "context" + "io" + "time" + + "google.golang.org/grpc" +) + +// UnaryClientInterceptor is a gRPC client-side interceptor that provides reporting for Unary RPCs. +func UnaryClientInterceptor(reportable ClientReportable) grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + r := newReport(Unary, method) + reporter, newCtx := reportable.ClientReporter(ctx, CallMeta{ReqProtoOrNil: req, Typ: r.rpcType, Service: r.service, Method: r.method}) + + reporter.PostMsgSend(req, nil, time.Since(r.startTime)) + err := invoker(newCtx, method, req, reply, cc, opts...) + reporter.PostMsgReceive(reply, err, time.Since(r.startTime)) + reporter.PostCall(err, time.Since(r.startTime)) + return err + } +} + +// StreamClientInterceptor is a gRPC client-side interceptor that provides reporting for Stream RPCs. +func StreamClientInterceptor(reportable ClientReportable) grpc.StreamClientInterceptor { + return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + r := newReport(clientStreamType(desc), method) + reporter, newCtx := reportable.ClientReporter(ctx, CallMeta{ReqProtoOrNil: nil, Typ: r.rpcType, Service: r.service, Method: r.method}) + + clientStream, err := streamer(newCtx, desc, cc, method, opts...) + if err != nil { + reporter.PostCall(err, time.Since(r.startTime)) + return nil, err + } + return &monitoredClientStream{ClientStream: clientStream, startTime: r.startTime, reporter: reporter}, nil + } +} + +func clientStreamType(desc *grpc.StreamDesc) GRPCType { + if desc.ClientStreams && !desc.ServerStreams { + return ClientStream + } else if !desc.ClientStreams && desc.ServerStreams { + return ServerStream + } + return BidiStream +} + +// monitoredClientStream wraps grpc.ClientStream allowing each Sent/Recv of message to report. +type monitoredClientStream struct { + grpc.ClientStream + + startTime time.Time + reporter Reporter +} + +func (s *monitoredClientStream) SendMsg(m interface{}) error { + start := time.Now() + err := s.ClientStream.SendMsg(m) + s.reporter.PostMsgSend(m, err, time.Since(start)) + return err +} + +func (s *monitoredClientStream) RecvMsg(m interface{}) error { + start := time.Now() + err := s.ClientStream.RecvMsg(m) + s.reporter.PostMsgReceive(m, err, time.Since(start)) + + if err == nil { + return nil + } + var postErr error + if err != io.EOF { + postErr = err + } + s.reporter.PostCall(postErr, time.Since(s.startTime)) + return err +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go new file mode 100644 index 000000000..2608b9a4f --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go @@ -0,0 +1,12 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +// +/* +interceptor is an internal package used by higher level middlewares. It allows injecting custom code in various +places of the gRPC lifecycle. + +This particular package is intended for use by other middleware, metric, logging or otherwise. +This allows code to be shared between different implementations. +*/ +package interceptors diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go new file mode 100644 index 000000000..cc3b4f136 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go @@ -0,0 +1,116 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +package interceptors + +import ( + "context" + "fmt" + "strings" + "time" + + "google.golang.org/grpc/codes" +) + +type GRPCType string + +// Timer is a helper interface to time functions. +// Useful for interceptors to record the total +// time elapsed since completion of a call. +type Timer interface { + ObserveDuration() time.Duration +} + +// zeroTimer. +type zeroTimer struct { +} + +func (zeroTimer) ObserveDuration() time.Duration { + return 0 +} + +var EmptyTimer = &zeroTimer{} + +const ( + Unary GRPCType = "unary" + ClientStream GRPCType = "client_stream" + ServerStream GRPCType = "server_stream" + BidiStream GRPCType = "bidi_stream" +) + +var ( + AllCodes = []codes.Code{ + codes.OK, codes.Canceled, codes.Unknown, codes.InvalidArgument, codes.DeadlineExceeded, codes.NotFound, + codes.AlreadyExists, codes.PermissionDenied, codes.Unauthenticated, codes.ResourceExhausted, + codes.FailedPrecondition, codes.Aborted, codes.OutOfRange, codes.Unimplemented, codes.Internal, + codes.Unavailable, codes.DataLoss, + } +) + +func SplitMethodName(fullMethod string) (string, string) { + fullMethod = strings.TrimPrefix(fullMethod, "/") // remove leading slash + if i := strings.Index(fullMethod, "/"); i >= 0 { + return fullMethod[:i], fullMethod[i+1:] + } + return "unknown", "unknown" +} + +type CallMeta struct { + ReqProtoOrNil interface{} + Typ GRPCType + Service string + Method string +} + +func (c CallMeta) FullMethod() string { + return fmt.Sprintf("/%s/%s", c.Service, c.Method) +} + +type ClientReportable interface { + ClientReporter(context.Context, CallMeta) (Reporter, context.Context) +} + +type ServerReportable interface { + ServerReporter(context.Context, CallMeta) (Reporter, context.Context) +} + +// CommonReportableFunc helper allows an easy way to implement reporter with common client and server logic. +type CommonReportableFunc func(ctx context.Context, c CallMeta, isClient bool) (Reporter, context.Context) + +func (f CommonReportableFunc) ClientReporter(ctx context.Context, c CallMeta) (Reporter, context.Context) { + return f(ctx, c, true) +} + +func (f CommonReportableFunc) ServerReporter(ctx context.Context, c CallMeta) (Reporter, context.Context) { + return f(ctx, c, false) +} + +type Reporter interface { + PostCall(err error, rpcDuration time.Duration) + PostMsgSend(reqProto interface{}, err error, sendDuration time.Duration) + PostMsgReceive(replyProto interface{}, err error, recvDuration time.Duration) +} + +var _ Reporter = NoopReporter{} + +type NoopReporter struct{} + +func (NoopReporter) PostCall(error, time.Duration) {} +func (NoopReporter) PostMsgSend(interface{}, error, time.Duration) {} +func (NoopReporter) PostMsgReceive(interface{}, error, time.Duration) {} + +type report struct { + rpcType GRPCType + service string + method string + startTime time.Time +} + +func newReport(typ GRPCType, fullMethod string) report { + r := report{ + startTime: time.Now(), + rpcType: typ, + } + r.service, r.method = SplitMethodName(fullMethod) + return r +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go new file mode 100644 index 000000000..1fcb8e4e9 --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go @@ -0,0 +1,74 @@ +// Copyright (c) The go-grpc-middleware Authors. +// Licensed under the Apache License 2.0. + +// Go gRPC Middleware monitoring interceptors for server-side gRPC. + +package interceptors + +import ( + "context" + "time" + + "google.golang.org/grpc" +) + +// UnaryServerInterceptor is a gRPC server-side interceptor that provides reporting for Unary RPCs. +func UnaryServerInterceptor(reportable ServerReportable) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + r := newReport(Unary, info.FullMethod) + reporter, newCtx := reportable.ServerReporter(ctx, CallMeta{ReqProtoOrNil: req, Typ: r.rpcType, Service: r.service, Method: r.method}) + + reporter.PostMsgReceive(req, nil, time.Since(r.startTime)) + resp, err := handler(newCtx, req) + reporter.PostMsgSend(resp, err, time.Since(r.startTime)) + + reporter.PostCall(err, time.Since(r.startTime)) + return resp, err + } +} + +// StreamServerInterceptor is a gRPC server-side interceptor that provides reporting for Streaming RPCs. +func StreamServerInterceptor(reportable ServerReportable) grpc.StreamServerInterceptor { + return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + r := newReport(ServerStream, info.FullMethod) + reporter, newCtx := reportable.ServerReporter(ss.Context(), CallMeta{ReqProtoOrNil: nil, Typ: StreamRPCType(info), Service: r.service, Method: r.method}) + err := handler(srv, &monitoredServerStream{ServerStream: ss, newCtx: newCtx, reporter: reporter}) + reporter.PostCall(err, time.Since(r.startTime)) + return err + } +} + +func StreamRPCType(info *grpc.StreamServerInfo) GRPCType { + if info.IsClientStream && !info.IsServerStream { + return ClientStream + } else if !info.IsClientStream && info.IsServerStream { + return ServerStream + } + return BidiStream +} + +// monitoredStream wraps grpc.ServerStream allowing each Sent/Recv of message to report. +type monitoredServerStream struct { + grpc.ServerStream + + newCtx context.Context + reporter Reporter +} + +func (s *monitoredServerStream) Context() context.Context { + return s.newCtx +} + +func (s *monitoredServerStream) SendMsg(m interface{}) error { + start := time.Now() + err := s.ServerStream.SendMsg(m) + s.reporter.PostMsgSend(m, err, time.Since(start)) + return err +} + +func (s *monitoredServerStream) RecvMsg(m interface{}) error { + start := time.Now() + err := s.ServerStream.RecvMsg(m) + s.reporter.PostMsgReceive(m, err, time.Since(start)) + return err +} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.gitignore b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.gitignore deleted file mode 100644 index 2233cff9d..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.gitignore +++ /dev/null @@ -1,201 +0,0 @@ -#vendor -vendor/ - -# Created by .ignore support plugin (hsz.mobi) -coverage.txt -### Go template -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof -### Windows template -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk -### Kate template -# Swap Files # -.*.kate-swp -.swp.* -### SublimeText template -# cache files for sublime text -*.tmlanguage.cache -*.tmPreferences.cache -*.stTheme.cache - -# workspace files are user-specific -*.sublime-workspace - -# project files should be checked into the repository, unless a significant -# proportion of contributors will probably not be using SublimeText -# *.sublime-project - -# sftp configuration file -sftp-config.json -### Linux template -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: -.idea -.idea/tasks.xml -.idea/dictionaries -.idea/vcs.xml -.idea/jsLibraryMappings.xml - -# Sensitive or high-churn files: -.idea/dataSources.ids -.idea/dataSources.xml -.idea/dataSources.local.xml -.idea/sqlDataSources.xml -.idea/dynamic.xml -.idea/uiDesigner.xml - -# Gradle: -.idea/gradle.xml -.idea/libraries - -# Mongo Explorer plugin: -.idea/mongoSettings.xml - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties -### Xcode template -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## Build generated -build/ -DerivedData/ - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata/ - -## Other -*.moved-aside -*.xccheckout -*.xcscmblueprint -### Eclipse template - -.metadata -bin/ -tmp/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.settings/ -.loadpath -.recommenders - -# Eclipse Core -.project - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# PyDev specific (Python IDE for Eclipse) -*.pydevproject - -# CDT-specific (C/C++ Development Tooling) -.cproject - -# JDT-specific (Eclipse Java Development Tools) -.classpath - -# Java annotation processor (APT) -.factorypath - -# PDT-specific (PHP Development Tools) -.buildpath - -# sbteclipse plugin -.target - -# Tern plugin -.tern-project - -# TeXlipse plugin -.texlipse - -# STS (Spring Tool Suite) -.springBeans - -# Code Recommenders -.recommenders/ - diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.travis.yml b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.travis.yml deleted file mode 100644 index 2a845b96a..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -sudo: false -language: go -# * github.com/grpc/grpc-go still supports go1.6 -# - When we drop support for go1.6 we can remove golang.org/x/net/context -# below as it is part of the Go std library since go1.7 -# * github.com/prometheus/client_golang already requires at least go1.7 since -# September 2017 -go: - - 1.6.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x - - master - -install: - - go get github.com/prometheus/client_golang/prometheus - - go get google.golang.org/grpc - - go get golang.org/x/net/context - - go get github.com/stretchr/testify -script: - - make test - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/CHANGELOG.md b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/CHANGELOG.md deleted file mode 100644 index 19a8059e1..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/CHANGELOG.md +++ /dev/null @@ -1,24 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [1.2.0](https://github.com/grpc-ecosystem/go-grpc-prometheus/releases/tag/v1.2.0) - 2018-06-04 - -### Added - -* Provide metrics object as `prometheus.Collector`, for conventional metric registration. -* Support non-default/global Prometheus registry. -* Allow configuring counters with `prometheus.CounterOpts`. - -### Changed - -* Remove usage of deprecated `grpc.Code()`. -* Remove usage of deprecated `grpc.Errorf` and replace with `status.Errorf`. - ---- - -This changelog was started with version `v1.2.0`, for earlier versions refer to the respective [GitHub releases](https://github.com/grpc-ecosystem/go-grpc-prometheus/releases). diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/README.md b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/README.md deleted file mode 100644 index 499c58355..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/README.md +++ /dev/null @@ -1,247 +0,0 @@ -# Go gRPC Interceptors for Prometheus monitoring - -[![Travis Build](https://travis-ci.org/grpc-ecosystem/go-grpc-prometheus.svg)](https://travis-ci.org/grpc-ecosystem/go-grpc-prometheus) -[![Go Report Card](https://goreportcard.com/badge/github.com/grpc-ecosystem/go-grpc-prometheus)](http://goreportcard.com/report/grpc-ecosystem/go-grpc-prometheus) -[![GoDoc](http://img.shields.io/badge/GoDoc-Reference-blue.svg)](https://godoc.org/github.com/grpc-ecosystem/go-grpc-prometheus) -[![SourceGraph](https://sourcegraph.com/github.com/grpc-ecosystem/go-grpc-prometheus/-/badge.svg)](https://sourcegraph.com/github.com/grpc-ecosystem/go-grpc-prometheus/?badge) -[![codecov](https://codecov.io/gh/grpc-ecosystem/go-grpc-prometheus/branch/master/graph/badge.svg)](https://codecov.io/gh/grpc-ecosystem/go-grpc-prometheus) -[![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) - -[Prometheus](https://prometheus.io/) monitoring for your [gRPC Go](https://github.com/grpc/grpc-go) servers and clients. - -A sister implementation for [gRPC Java](https://github.com/grpc/grpc-java) (same metrics, same semantics) is in [grpc-ecosystem/java-grpc-prometheus](https://github.com/grpc-ecosystem/java-grpc-prometheus). - -## Interceptors - -[gRPC Go](https://github.com/grpc/grpc-go) recently acquired support for Interceptors, i.e. middleware that is executed -by a gRPC Server before the request is passed onto the user's application logic. It is a perfect way to implement -common patterns: auth, logging and... monitoring. - -To use Interceptors in chains, please see [`go-grpc-middleware`](https://github.com/mwitkow/go-grpc-middleware). - -## Usage - -There are two types of interceptors: client-side and server-side. This package provides monitoring Interceptors for both. - -### Server-side - -```go -import "github.com/grpc-ecosystem/go-grpc-prometheus" -... - // Initialize your gRPC server's interceptor. - myServer := grpc.NewServer( - grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor), - grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor), - ) - // Register your gRPC service implementations. - myservice.RegisterMyServiceServer(s.server, &myServiceImpl{}) - // After all your registrations, make sure all of the Prometheus metrics are initialized. - grpc_prometheus.Register(myServer) - // Register Prometheus metrics handler. - http.Handle("/metrics", promhttp.Handler()) -... -``` - -### Client-side - -```go -import "github.com/grpc-ecosystem/go-grpc-prometheus" -... - clientConn, err = grpc.Dial( - address, - grpc.WithUnaryInterceptor(grpc_prometheus.UnaryClientInterceptor), - grpc.WithStreamInterceptor(grpc_prometheus.StreamClientInterceptor) - ) - client = pb_testproto.NewTestServiceClient(clientConn) - resp, err := client.PingEmpty(s.ctx, &myservice.Request{Msg: "hello"}) -... -``` - -# Metrics - -## Labels - -All server-side metrics start with `grpc_server` as Prometheus subsystem name. All client-side metrics start with `grpc_client`. Both of them have mirror-concepts. Similarly all methods -contain the same rich labels: - - * `grpc_service` - the [gRPC service](http://www.grpc.io/docs/#defining-a-service) name, which is the combination of protobuf `package` and - the `grpc_service` section name. E.g. for `package = mwitkow.testproto` and - `service TestService` the label will be `grpc_service="mwitkow.testproto.TestService"` - * `grpc_method` - the name of the method called on the gRPC service. E.g. - `grpc_method="Ping"` - * `grpc_type` - the gRPC [type of request](http://www.grpc.io/docs/guides/concepts.html#rpc-life-cycle). - Differentiating between the two is important especially for latency measurements. - - - `unary` is single request, single response RPC - - `client_stream` is a multi-request, single response RPC - - `server_stream` is a single request, multi-response RPC - - `bidi_stream` is a multi-request, multi-response RPC - - -Additionally for completed RPCs, the following labels are used: - - * `grpc_code` - the human-readable [gRPC status code](https://github.com/grpc/grpc-go/blob/master/codes/codes.go). - The list of all statuses is to long, but here are some common ones: - - - `OK` - means the RPC was successful - - `IllegalArgument` - RPC contained bad values - - `Internal` - server-side error not disclosed to the clients - -## Counters - -The counters and their up to date documentation is in [server_reporter.go](server_reporter.go) and [client_reporter.go](client_reporter.go) -the respective Prometheus handler (usually `/metrics`). - -For the purpose of this documentation we will only discuss `grpc_server` metrics. The `grpc_client` ones contain mirror concepts. - -For simplicity, let's assume we're tracking a single server-side RPC call of [`mwitkow.testproto.TestService`](examples/testproto/test.proto), -calling the method `PingList`. The call succeeds and returns 20 messages in the stream. - -First, immediately after the server receives the call it will increment the -`grpc_server_started_total` and start the handling time clock (if histograms are enabled). - -```jsoniq -grpc_server_started_total{grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream"} 1 -``` - -Then the user logic gets invoked. It receives one message from the client containing the request -(it's a `server_stream`): - -```jsoniq -grpc_server_msg_received_total{grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream"} 1 -``` - -The user logic may return an error, or send multiple messages back to the client. In this case, on -each of the 20 messages sent back, a counter will be incremented: - -```jsoniq -grpc_server_msg_sent_total{grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream"} 20 -``` - -After the call completes, its status (`OK` or other [gRPC status code](https://github.com/grpc/grpc-go/blob/master/codes/codes.go)) -and the relevant call labels increment the `grpc_server_handled_total` counter. - -```jsoniq -grpc_server_handled_total{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream"} 1 -``` - -## Histograms - -[Prometheus histograms](https://prometheus.io/docs/concepts/metric_types/#histogram) are a great way -to measure latency distributions of your RPCs. However, since it is bad practice to have metrics -of [high cardinality](https://prometheus.io/docs/practices/instrumentation/#do-not-overuse-labels) -the latency monitoring metrics are disabled by default. To enable them please call the following -in your server initialization code: - -```jsoniq -grpc_prometheus.EnableHandlingTimeHistogram() -``` - -After the call completes, its handling time will be recorded in a [Prometheus histogram](https://prometheus.io/docs/concepts/metric_types/#histogram) -variable `grpc_server_handling_seconds`. The histogram variable contains three sub-metrics: - - * `grpc_server_handling_seconds_count` - the count of all completed RPCs by status and method - * `grpc_server_handling_seconds_sum` - cumulative time of RPCs by status and method, useful for - calculating average handling times - * `grpc_server_handling_seconds_bucket` - contains the counts of RPCs by status and method in respective - handling-time buckets. These buckets can be used by Prometheus to estimate SLAs (see [here](https://prometheus.io/docs/practices/histograms/)) - -The counter values will look as follows: - -```jsoniq -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.005"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.01"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.025"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.05"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.1"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.25"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="0.5"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="1"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="2.5"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="5"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="10"} 1 -grpc_server_handling_seconds_bucket{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream",le="+Inf"} 1 -grpc_server_handling_seconds_sum{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream"} 0.0003866430000000001 -grpc_server_handling_seconds_count{grpc_code="OK",grpc_method="PingList",grpc_service="mwitkow.testproto.TestService",grpc_type="server_stream"} 1 -``` - - -## Useful query examples - -Prometheus philosophy is to provide raw metrics to the monitoring system, and -let the aggregations be handled there. The verbosity of above metrics make it possible to have that -flexibility. Here's a couple of useful monitoring queries: - - -### request inbound rate -```jsoniq -sum(rate(grpc_server_started_total{job="foo"}[1m])) by (grpc_service) -``` -For `job="foo"` (common label to differentiate between Prometheus monitoring targets), calculate the -rate of requests per second (1 minute window) for each gRPC `grpc_service` that the job has. Please note -how the `grpc_method` is being omitted here: all methods of a given gRPC service will be summed together. - -### unary request error rate -```jsoniq -sum(rate(grpc_server_handled_total{job="foo",grpc_type="unary",grpc_code!="OK"}[1m])) by (grpc_service) -``` -For `job="foo"`, calculate the per-`grpc_service` rate of `unary` (1:1) RPCs that failed, i.e. the -ones that didn't finish with `OK` code. - -### unary request error percentage -```jsoniq -sum(rate(grpc_server_handled_total{job="foo",grpc_type="unary",grpc_code!="OK"}[1m])) by (grpc_service) - / -sum(rate(grpc_server_started_total{job="foo",grpc_type="unary"}[1m])) by (grpc_service) - * 100.0 -``` -For `job="foo"`, calculate the percentage of failed requests by service. It's easy to notice that -this is a combination of the two above examples. This is an example of a query you would like to -[alert on](https://prometheus.io/docs/alerting/rules/) in your system for SLA violations, e.g. -"no more than 1% requests should fail". - -### average response stream size -```jsoniq -sum(rate(grpc_server_msg_sent_total{job="foo",grpc_type="server_stream"}[10m])) by (grpc_service) - / -sum(rate(grpc_server_started_total{job="foo",grpc_type="server_stream"}[10m])) by (grpc_service) -``` -For `job="foo"` what is the `grpc_service`-wide `10m` average of messages returned for all ` -server_stream` RPCs. This allows you to track the stream sizes returned by your system, e.g. allows -you to track when clients started to send "wide" queries that ret -Note the divisor is the number of started RPCs, in order to account for in-flight requests. - -### 99%-tile latency of unary requests -```jsoniq -histogram_quantile(0.99, - sum(rate(grpc_server_handling_seconds_bucket{job="foo",grpc_type="unary"}[5m])) by (grpc_service,le) -) -``` -For `job="foo"`, returns an 99%-tile [quantile estimation](https://prometheus.io/docs/practices/histograms/#quantiles) -of the handling time of RPCs per service. Please note the `5m` rate, this means that the quantile -estimation will take samples in a rolling `5m` window. When combined with other quantiles -(e.g. 50%, 90%), this query gives you tremendous insight into the responsiveness of your system -(e.g. impact of caching). - -### percentage of slow unary queries (>250ms) -```jsoniq -100.0 - ( -sum(rate(grpc_server_handling_seconds_bucket{job="foo",grpc_type="unary",le="0.25"}[5m])) by (grpc_service) - / -sum(rate(grpc_server_handling_seconds_count{job="foo",grpc_type="unary"}[5m])) by (grpc_service) -) * 100.0 -``` -For `job="foo"` calculate the by-`grpc_service` fraction of slow requests that took longer than `0.25` -seconds. This query is relatively complex, since the Prometheus aggregations use `le` (less or equal) -buckets, meaning that counting "fast" requests fractions is easier. However, simple maths helps. -This is an example of a query you would like to alert on in your system for SLA violations, -e.g. "less than 1% of requests are slower than 250ms". - - -## Status - -This code has been used since August 2015 as the basis for monitoring of *production* gRPC micro services at [Improbable](https://improbable.io). - -## License - -`go-grpc-prometheus` is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details. diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client.go deleted file mode 100644 index 751a4c72d..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 Michal Witkowski. All Rights Reserved. -// See LICENSE for licensing terms. - -// gRPC Prometheus monitoring interceptors for client-side gRPC. - -package grpc_prometheus - -import ( - prom "github.com/prometheus/client_golang/prometheus" -) - -var ( - // DefaultClientMetrics is the default instance of ClientMetrics. It is - // intended to be used in conjunction the default Prometheus metrics - // registry. - DefaultClientMetrics = NewClientMetrics() - - // UnaryClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Unary RPCs. - UnaryClientInterceptor = DefaultClientMetrics.UnaryClientInterceptor() - - // StreamClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Streaming RPCs. - StreamClientInterceptor = DefaultClientMetrics.StreamClientInterceptor() -) - -func init() { - prom.MustRegister(DefaultClientMetrics.clientStartedCounter) - prom.MustRegister(DefaultClientMetrics.clientHandledCounter) - prom.MustRegister(DefaultClientMetrics.clientStreamMsgReceived) - prom.MustRegister(DefaultClientMetrics.clientStreamMsgSent) -} - -// EnableClientHandlingTimeHistogram turns on recording of handling time of -// RPCs. Histogram metrics can be very expensive for Prometheus to retain and -// query. This function acts on the DefaultClientMetrics variable and the -// default Prometheus metrics registry. -func EnableClientHandlingTimeHistogram(opts ...HistogramOption) { - DefaultClientMetrics.EnableClientHandlingTimeHistogram(opts...) - prom.Register(DefaultClientMetrics.clientHandledHistogram) -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_metrics.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_metrics.go deleted file mode 100644 index 9b476f983..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_metrics.go +++ /dev/null @@ -1,170 +0,0 @@ -package grpc_prometheus - -import ( - "io" - - prom "github.com/prometheus/client_golang/prometheus" - "golang.org/x/net/context" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -// ClientMetrics represents a collection of metrics to be registered on a -// Prometheus metrics registry for a gRPC client. -type ClientMetrics struct { - clientStartedCounter *prom.CounterVec - clientHandledCounter *prom.CounterVec - clientStreamMsgReceived *prom.CounterVec - clientStreamMsgSent *prom.CounterVec - clientHandledHistogramEnabled bool - clientHandledHistogramOpts prom.HistogramOpts - clientHandledHistogram *prom.HistogramVec -} - -// NewClientMetrics returns a ClientMetrics object. Use a new instance of -// ClientMetrics when not using the default Prometheus metrics registry, for -// example when wanting to control which metrics are added to a registry as -// opposed to automatically adding metrics via init functions. -func NewClientMetrics(counterOpts ...CounterOption) *ClientMetrics { - opts := counterOptions(counterOpts) - return &ClientMetrics{ - clientStartedCounter: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_client_started_total", - Help: "Total number of RPCs started on the client.", - }), []string{"grpc_type", "grpc_service", "grpc_method"}), - - clientHandledCounter: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_client_handled_total", - Help: "Total number of RPCs completed by the client, regardless of success or failure.", - }), []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"}), - - clientStreamMsgReceived: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_client_msg_received_total", - Help: "Total number of RPC stream messages received by the client.", - }), []string{"grpc_type", "grpc_service", "grpc_method"}), - - clientStreamMsgSent: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_client_msg_sent_total", - Help: "Total number of gRPC stream messages sent by the client.", - }), []string{"grpc_type", "grpc_service", "grpc_method"}), - - clientHandledHistogramEnabled: false, - clientHandledHistogramOpts: prom.HistogramOpts{ - Name: "grpc_client_handling_seconds", - Help: "Histogram of response latency (seconds) of the gRPC until it is finished by the application.", - Buckets: prom.DefBuckets, - }, - clientHandledHistogram: nil, - } -} - -// 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. -func (m *ClientMetrics) Describe(ch chan<- *prom.Desc) { - m.clientStartedCounter.Describe(ch) - m.clientHandledCounter.Describe(ch) - m.clientStreamMsgReceived.Describe(ch) - m.clientStreamMsgSent.Describe(ch) - if m.clientHandledHistogramEnabled { - m.clientHandledHistogram.Describe(ch) - } -} - -// 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. -func (m *ClientMetrics) Collect(ch chan<- prom.Metric) { - m.clientStartedCounter.Collect(ch) - m.clientHandledCounter.Collect(ch) - m.clientStreamMsgReceived.Collect(ch) - m.clientStreamMsgSent.Collect(ch) - if m.clientHandledHistogramEnabled { - m.clientHandledHistogram.Collect(ch) - } -} - -// EnableClientHandlingTimeHistogram turns on recording of handling time of RPCs. -// Histogram metrics can be very expensive for Prometheus to retain and query. -func (m *ClientMetrics) EnableClientHandlingTimeHistogram(opts ...HistogramOption) { - for _, o := range opts { - o(&m.clientHandledHistogramOpts) - } - if !m.clientHandledHistogramEnabled { - m.clientHandledHistogram = prom.NewHistogramVec( - m.clientHandledHistogramOpts, - []string{"grpc_type", "grpc_service", "grpc_method"}, - ) - } - m.clientHandledHistogramEnabled = true -} - -// UnaryClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Unary RPCs. -func (m *ClientMetrics) UnaryClientInterceptor() func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - monitor := newClientReporter(m, Unary, method) - monitor.SentMessage() - err := invoker(ctx, method, req, reply, cc, opts...) - if err != nil { - monitor.ReceivedMessage() - } - st, _ := status.FromError(err) - monitor.Handled(st.Code()) - return err - } -} - -// StreamClientInterceptor is a gRPC client-side interceptor that provides Prometheus monitoring for Streaming RPCs. -func (m *ClientMetrics) StreamClientInterceptor() func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { - return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { - monitor := newClientReporter(m, clientStreamType(desc), method) - clientStream, err := streamer(ctx, desc, cc, method, opts...) - if err != nil { - st, _ := status.FromError(err) - monitor.Handled(st.Code()) - return nil, err - } - return &monitoredClientStream{clientStream, monitor}, nil - } -} - -func clientStreamType(desc *grpc.StreamDesc) grpcType { - if desc.ClientStreams && !desc.ServerStreams { - return ClientStream - } else if !desc.ClientStreams && desc.ServerStreams { - return ServerStream - } - return BidiStream -} - -// monitoredClientStream wraps grpc.ClientStream allowing each Sent/Recv of message to increment counters. -type monitoredClientStream struct { - grpc.ClientStream - monitor *clientReporter -} - -func (s *monitoredClientStream) SendMsg(m interface{}) error { - err := s.ClientStream.SendMsg(m) - if err == nil { - s.monitor.SentMessage() - } - return err -} - -func (s *monitoredClientStream) RecvMsg(m interface{}) error { - err := s.ClientStream.RecvMsg(m) - if err == nil { - s.monitor.ReceivedMessage() - } else if err == io.EOF { - s.monitor.Handled(codes.OK) - } else { - st, _ := status.FromError(err) - s.monitor.Handled(st.Code()) - } - return err -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_reporter.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_reporter.go deleted file mode 100644 index cbf153229..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/client_reporter.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 Michal Witkowski. All Rights Reserved. -// See LICENSE for licensing terms. - -package grpc_prometheus - -import ( - "time" - - "google.golang.org/grpc/codes" -) - -type clientReporter struct { - metrics *ClientMetrics - rpcType grpcType - serviceName string - methodName string - startTime time.Time -} - -func newClientReporter(m *ClientMetrics, rpcType grpcType, fullMethod string) *clientReporter { - r := &clientReporter{ - metrics: m, - rpcType: rpcType, - } - if r.metrics.clientHandledHistogramEnabled { - r.startTime = time.Now() - } - r.serviceName, r.methodName = splitMethodName(fullMethod) - r.metrics.clientStartedCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc() - return r -} - -func (r *clientReporter) ReceivedMessage() { - r.metrics.clientStreamMsgReceived.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc() -} - -func (r *clientReporter) SentMessage() { - r.metrics.clientStreamMsgSent.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc() -} - -func (r *clientReporter) Handled(code codes.Code) { - r.metrics.clientHandledCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName, code.String()).Inc() - if r.metrics.clientHandledHistogramEnabled { - r.metrics.clientHandledHistogram.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Observe(time.Since(r.startTime).Seconds()) - } -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/makefile b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/makefile deleted file mode 100644 index 74c084223..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/makefile +++ /dev/null @@ -1,16 +0,0 @@ -SHELL="/bin/bash" - -GOFILES_NOVENDOR = $(shell go list ./... | grep -v /vendor/) - -all: vet fmt test - -fmt: - go fmt $(GOFILES_NOVENDOR) - -vet: - go vet $(GOFILES_NOVENDOR) - -test: vet - ./scripts/test_all.sh - -.PHONY: all vet test diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/metric_options.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/metric_options.go deleted file mode 100644 index 9d51aec98..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/metric_options.go +++ /dev/null @@ -1,41 +0,0 @@ -package grpc_prometheus - -import ( - prom "github.com/prometheus/client_golang/prometheus" -) - -// A CounterOption lets you add options to Counter metrics using With* funcs. -type CounterOption func(*prom.CounterOpts) - -type counterOptions []CounterOption - -func (co counterOptions) apply(o prom.CounterOpts) prom.CounterOpts { - for _, f := range co { - f(&o) - } - return o -} - -// WithConstLabels allows you to add ConstLabels to Counter metrics. -func WithConstLabels(labels prom.Labels) CounterOption { - return func(o *prom.CounterOpts) { - o.ConstLabels = labels - } -} - -// A HistogramOption lets you add options to Histogram metrics using With* -// funcs. -type HistogramOption func(*prom.HistogramOpts) - -// WithHistogramBuckets allows you to specify custom bucket ranges for histograms if EnableHandlingTimeHistogram is on. -func WithHistogramBuckets(buckets []float64) HistogramOption { - return func(o *prom.HistogramOpts) { o.Buckets = buckets } -} - -// WithHistogramConstLabels allows you to add custom ConstLabels to -// histograms metrics. -func WithHistogramConstLabels(labels prom.Labels) HistogramOption { - return func(o *prom.HistogramOpts) { - o.ConstLabels = labels - } -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server.go deleted file mode 100644 index 322f99046..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Michal Witkowski. All Rights Reserved. -// See LICENSE for licensing terms. - -// gRPC Prometheus monitoring interceptors for server-side gRPC. - -package grpc_prometheus - -import ( - prom "github.com/prometheus/client_golang/prometheus" - "google.golang.org/grpc" -) - -var ( - // DefaultServerMetrics is the default instance of ServerMetrics. It is - // intended to be used in conjunction the default Prometheus metrics - // registry. - DefaultServerMetrics = NewServerMetrics() - - // UnaryServerInterceptor is a gRPC server-side interceptor that provides Prometheus monitoring for Unary RPCs. - UnaryServerInterceptor = DefaultServerMetrics.UnaryServerInterceptor() - - // StreamServerInterceptor is a gRPC server-side interceptor that provides Prometheus monitoring for Streaming RPCs. - StreamServerInterceptor = DefaultServerMetrics.StreamServerInterceptor() -) - -func init() { - prom.MustRegister(DefaultServerMetrics.serverStartedCounter) - prom.MustRegister(DefaultServerMetrics.serverHandledCounter) - prom.MustRegister(DefaultServerMetrics.serverStreamMsgReceived) - prom.MustRegister(DefaultServerMetrics.serverStreamMsgSent) -} - -// Register takes a gRPC server and pre-initializes all counters to 0. This -// allows for easier monitoring in Prometheus (no missing metrics), and should -// be called *after* all services have been registered with the server. This -// function acts on the DefaultServerMetrics variable. -func Register(server *grpc.Server) { - DefaultServerMetrics.InitializeMetrics(server) -} - -// EnableHandlingTimeHistogram turns on recording of handling time -// of RPCs. Histogram metrics can be very expensive for Prometheus -// to retain and query. This function acts on the DefaultServerMetrics -// variable and the default Prometheus metrics registry. -func EnableHandlingTimeHistogram(opts ...HistogramOption) { - DefaultServerMetrics.EnableHandlingTimeHistogram(opts...) - prom.Register(DefaultServerMetrics.serverHandledHistogram) -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_metrics.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_metrics.go deleted file mode 100644 index 5b1467e7a..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_metrics.go +++ /dev/null @@ -1,185 +0,0 @@ -package grpc_prometheus - -import ( - prom "github.com/prometheus/client_golang/prometheus" - "golang.org/x/net/context" - "google.golang.org/grpc" - "google.golang.org/grpc/status" -) - -// ServerMetrics represents a collection of metrics to be registered on a -// Prometheus metrics registry for a gRPC server. -type ServerMetrics struct { - serverStartedCounter *prom.CounterVec - serverHandledCounter *prom.CounterVec - serverStreamMsgReceived *prom.CounterVec - serverStreamMsgSent *prom.CounterVec - serverHandledHistogramEnabled bool - serverHandledHistogramOpts prom.HistogramOpts - serverHandledHistogram *prom.HistogramVec -} - -// NewServerMetrics returns a ServerMetrics object. Use a new instance of -// ServerMetrics when not using the default Prometheus metrics registry, for -// example when wanting to control which metrics are added to a registry as -// opposed to automatically adding metrics via init functions. -func NewServerMetrics(counterOpts ...CounterOption) *ServerMetrics { - opts := counterOptions(counterOpts) - return &ServerMetrics{ - serverStartedCounter: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_server_started_total", - Help: "Total number of RPCs started on the server.", - }), []string{"grpc_type", "grpc_service", "grpc_method"}), - serverHandledCounter: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_server_handled_total", - Help: "Total number of RPCs completed on the server, regardless of success or failure.", - }), []string{"grpc_type", "grpc_service", "grpc_method", "grpc_code"}), - serverStreamMsgReceived: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_server_msg_received_total", - Help: "Total number of RPC stream messages received on the server.", - }), []string{"grpc_type", "grpc_service", "grpc_method"}), - serverStreamMsgSent: prom.NewCounterVec( - opts.apply(prom.CounterOpts{ - Name: "grpc_server_msg_sent_total", - Help: "Total number of gRPC stream messages sent by the server.", - }), []string{"grpc_type", "grpc_service", "grpc_method"}), - serverHandledHistogramEnabled: false, - serverHandledHistogramOpts: prom.HistogramOpts{ - Name: "grpc_server_handling_seconds", - Help: "Histogram of response latency (seconds) of gRPC that had been application-level handled by the server.", - Buckets: prom.DefBuckets, - }, - serverHandledHistogram: nil, - } -} - -// EnableHandlingTimeHistogram enables histograms being registered when -// registering the ServerMetrics on a Prometheus registry. Histograms can be -// expensive on Prometheus servers. It takes options to configure histogram -// options such as the defined buckets. -func (m *ServerMetrics) EnableHandlingTimeHistogram(opts ...HistogramOption) { - for _, o := range opts { - o(&m.serverHandledHistogramOpts) - } - if !m.serverHandledHistogramEnabled { - m.serverHandledHistogram = prom.NewHistogramVec( - m.serverHandledHistogramOpts, - []string{"grpc_type", "grpc_service", "grpc_method"}, - ) - } - m.serverHandledHistogramEnabled = true -} - -// 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. -func (m *ServerMetrics) Describe(ch chan<- *prom.Desc) { - m.serverStartedCounter.Describe(ch) - m.serverHandledCounter.Describe(ch) - m.serverStreamMsgReceived.Describe(ch) - m.serverStreamMsgSent.Describe(ch) - if m.serverHandledHistogramEnabled { - m.serverHandledHistogram.Describe(ch) - } -} - -// 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. -func (m *ServerMetrics) Collect(ch chan<- prom.Metric) { - m.serverStartedCounter.Collect(ch) - m.serverHandledCounter.Collect(ch) - m.serverStreamMsgReceived.Collect(ch) - m.serverStreamMsgSent.Collect(ch) - if m.serverHandledHistogramEnabled { - m.serverHandledHistogram.Collect(ch) - } -} - -// UnaryServerInterceptor is a gRPC server-side interceptor that provides Prometheus monitoring for Unary RPCs. -func (m *ServerMetrics) UnaryServerInterceptor() func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - monitor := newServerReporter(m, Unary, info.FullMethod) - monitor.ReceivedMessage() - resp, err := handler(ctx, req) - st, _ := status.FromError(err) - monitor.Handled(st.Code()) - if err == nil { - monitor.SentMessage() - } - return resp, err - } -} - -// StreamServerInterceptor is a gRPC server-side interceptor that provides Prometheus monitoring for Streaming RPCs. -func (m *ServerMetrics) StreamServerInterceptor() func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - monitor := newServerReporter(m, streamRPCType(info), info.FullMethod) - err := handler(srv, &monitoredServerStream{ss, monitor}) - st, _ := status.FromError(err) - monitor.Handled(st.Code()) - return err - } -} - -// InitializeMetrics initializes all metrics, with their appropriate null -// value, for all gRPC methods registered on a gRPC server. This is useful, to -// ensure that all metrics exist when collecting and querying. -func (m *ServerMetrics) InitializeMetrics(server *grpc.Server) { - serviceInfo := server.GetServiceInfo() - for serviceName, info := range serviceInfo { - for _, mInfo := range info.Methods { - preRegisterMethod(m, serviceName, &mInfo) - } - } -} - -func streamRPCType(info *grpc.StreamServerInfo) grpcType { - if info.IsClientStream && !info.IsServerStream { - return ClientStream - } else if !info.IsClientStream && info.IsServerStream { - return ServerStream - } - return BidiStream -} - -// monitoredStream wraps grpc.ServerStream allowing each Sent/Recv of message to increment counters. -type monitoredServerStream struct { - grpc.ServerStream - monitor *serverReporter -} - -func (s *monitoredServerStream) SendMsg(m interface{}) error { - err := s.ServerStream.SendMsg(m) - if err == nil { - s.monitor.SentMessage() - } - return err -} - -func (s *monitoredServerStream) RecvMsg(m interface{}) error { - err := s.ServerStream.RecvMsg(m) - if err == nil { - s.monitor.ReceivedMessage() - } - return err -} - -// preRegisterMethod is invoked on Register of a Server, allowing all gRPC services labels to be pre-populated. -func preRegisterMethod(metrics *ServerMetrics, serviceName string, mInfo *grpc.MethodInfo) { - methodName := mInfo.Name - methodType := string(typeFromMethodInfo(mInfo)) - // These are just references (no increments), as just referencing will create the labels but not set values. - metrics.serverStartedCounter.GetMetricWithLabelValues(methodType, serviceName, methodName) - metrics.serverStreamMsgReceived.GetMetricWithLabelValues(methodType, serviceName, methodName) - metrics.serverStreamMsgSent.GetMetricWithLabelValues(methodType, serviceName, methodName) - if metrics.serverHandledHistogramEnabled { - metrics.serverHandledHistogram.GetMetricWithLabelValues(methodType, serviceName, methodName) - } - for _, code := range allCodes { - metrics.serverHandledCounter.GetMetricWithLabelValues(methodType, serviceName, methodName, code.String()) - } -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_reporter.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_reporter.go deleted file mode 100644 index aa9db5401..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/server_reporter.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 Michal Witkowski. All Rights Reserved. -// See LICENSE for licensing terms. - -package grpc_prometheus - -import ( - "time" - - "google.golang.org/grpc/codes" -) - -type serverReporter struct { - metrics *ServerMetrics - rpcType grpcType - serviceName string - methodName string - startTime time.Time -} - -func newServerReporter(m *ServerMetrics, rpcType grpcType, fullMethod string) *serverReporter { - r := &serverReporter{ - metrics: m, - rpcType: rpcType, - } - if r.metrics.serverHandledHistogramEnabled { - r.startTime = time.Now() - } - r.serviceName, r.methodName = splitMethodName(fullMethod) - r.metrics.serverStartedCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc() - return r -} - -func (r *serverReporter) ReceivedMessage() { - r.metrics.serverStreamMsgReceived.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc() -} - -func (r *serverReporter) SentMessage() { - r.metrics.serverStreamMsgSent.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Inc() -} - -func (r *serverReporter) Handled(code codes.Code) { - r.metrics.serverHandledCounter.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName, code.String()).Inc() - if r.metrics.serverHandledHistogramEnabled { - r.metrics.serverHandledHistogram.WithLabelValues(string(r.rpcType), r.serviceName, r.methodName).Observe(time.Since(r.startTime).Seconds()) - } -} diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/util.go b/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/util.go deleted file mode 100644 index 7987de35f..000000000 --- a/vendor/github.com/grpc-ecosystem/go-grpc-prometheus/util.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2016 Michal Witkowski. All Rights Reserved. -// See LICENSE for licensing terms. - -package grpc_prometheus - -import ( - "strings" - - "google.golang.org/grpc" - "google.golang.org/grpc/codes" -) - -type grpcType string - -const ( - Unary grpcType = "unary" - ClientStream grpcType = "client_stream" - ServerStream grpcType = "server_stream" - BidiStream grpcType = "bidi_stream" -) - -var ( - allCodes = []codes.Code{ - codes.OK, codes.Canceled, codes.Unknown, codes.InvalidArgument, codes.DeadlineExceeded, codes.NotFound, - codes.AlreadyExists, codes.PermissionDenied, codes.Unauthenticated, codes.ResourceExhausted, - codes.FailedPrecondition, codes.Aborted, codes.OutOfRange, codes.Unimplemented, codes.Internal, - codes.Unavailable, codes.DataLoss, - } -) - -func splitMethodName(fullMethodName string) (string, string) { - fullMethodName = strings.TrimPrefix(fullMethodName, "/") // remove leading slash - if i := strings.Index(fullMethodName, "/"); i >= 0 { - return fullMethodName[:i], fullMethodName[i+1:] - } - return "unknown", "unknown" -} - -func typeFromMethodInfo(mInfo *grpc.MethodInfo) grpcType { - if !mInfo.IsClientStream && !mInfo.IsServerStream { - return Unary - } - if mInfo.IsClientStream && !mInfo.IsServerStream { - return ClientStream - } - if !mInfo.IsClientStream && mInfo.IsServerStream { - return ServerStream - } - return BidiStream -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go index ac1ca3cf5..cf05079fb 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/collector.go @@ -69,9 +69,9 @@ type Collector interface { // 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) -// } +// 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 diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go index 00d70f09b..a912b75a0 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go @@ -51,7 +51,7 @@ type Counter interface { // 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 64 runes in total. +// than 128 runes in total. type ExemplarAdder interface { AddWithExemplar(value float64, exemplar Labels) } @@ -140,12 +140,13 @@ func (c *counter) get() float64 { } func (c *counter) Write(out *dto.Metric) error { - val := c.get() - + // Read the Exemplar first and the value second. This is to avoid a race condition + // where users see an exemplar for a not-yet-existing observation. var exemplar *dto.Exemplar if e := c.exemplar.Load(); e != nil { exemplar = e.(*dto.Exemplar) } + val := c.get() return populateMetric(CounterValue, val, c.labelPairs, exemplar, out) } @@ -245,7 +246,8 @@ func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) { // 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) +// +// myVec.WithLabelValues("404", "GET").Add(42) func (v *CounterVec) WithLabelValues(lvs ...string) Counter { c, err := v.GetMetricWithLabelValues(lvs...) if err != nil { @@ -256,7 +258,8 @@ func (v *CounterVec) WithLabelValues(lvs ...string) Counter { // 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) +// +// 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 { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 4bb816ab7..8bc5e44e2 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -20,6 +20,9 @@ import ( "strings" "github.com/cespare/xxhash/v2" + + "github.com/prometheus/client_golang/prometheus/internal" + //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/golang/protobuf/proto" "github.com/prometheus/common/model" @@ -154,7 +157,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * Value: proto.String(v), }) } - sort.Sort(labelPairSorter(d.constLabelPairs)) + sort.Sort(internal.LabelPairSorter(d.constLabelPairs)) return d } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go index 98450125d..811072cbd 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go @@ -21,55 +21,66 @@ // All exported functions and methods are safe to be used concurrently unless // specified otherwise. // -// A Basic Example +// # A Basic Example // // As a starting point, a very basic usage example: // -// package main -// -// import ( -// "log" -// "net/http" -// -// "github.com/prometheus/client_golang/prometheus" -// "github.com/prometheus/client_golang/prometheus/promhttp" -// ) -// -// var ( -// cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{ -// Name: "cpu_temperature_celsius", -// Help: "Current temperature of the CPU.", -// }) -// hdFailures = prometheus.NewCounterVec( -// prometheus.CounterOpts{ -// Name: "hd_errors_total", -// Help: "Number of hard-disk errors.", -// }, -// []string{"device"}, -// ) -// ) -// -// func init() { -// // Metrics have to be registered to be exposed: -// prometheus.MustRegister(cpuTemp) -// prometheus.MustRegister(hdFailures) -// } -// -// func main() { -// cpuTemp.Set(65.3) -// hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc() -// -// // The Handler function provides a default handler to expose metrics -// // via an HTTP server. "/metrics" is the usual endpoint for that. -// http.Handle("/metrics", promhttp.Handler()) -// log.Fatal(http.ListenAndServe(":8080", nil)) -// } -// +// package main +// +// import ( +// "log" +// "net/http" +// +// "github.com/prometheus/client_golang/prometheus" +// "github.com/prometheus/client_golang/prometheus/promhttp" +// ) +// +// type metrics struct { +// cpuTemp prometheus.Gauge +// hdFailures *prometheus.CounterVec +// } +// +// func NewMetrics(reg prometheus.Registerer) *metrics { +// m := &metrics{ +// cpuTemp: prometheus.NewGauge(prometheus.GaugeOpts{ +// Name: "cpu_temperature_celsius", +// Help: "Current temperature of the CPU.", +// }), +// hdFailures: prometheus.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "hd_errors_total", +// Help: "Number of hard-disk errors.", +// }, +// []string{"device"}, +// ), +// } +// reg.MustRegister(m.cpuTemp) +// reg.MustRegister(m.hdFailures) +// return m +// } +// +// func main() { +// // Create a non-global registry. +// reg := prometheus.NewRegistry() +// +// // Create new metrics and register them using the custom registry. +// m := NewMetrics(reg) +// // Set values for the new created metrics. +// m.cpuTemp.Set(65.3) +// m.hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc() +// +// // Expose metrics and custom registry via an HTTP server +// // using the HandleFor function. "/metrics" is the usual endpoint for that. +// http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg})) +// log.Fatal(http.ListenAndServe(":8080", nil)) +// } // // This is a complete program that exports two metrics, a Gauge and a Counter, // the latter with a label attached to turn it into a (one-dimensional) vector. +// It register the metrics using a custom registry and exposes them via an HTTP server +// on the /metrics endpoint. // -// Metrics +// # Metrics // // The number of exported identifiers in this package might appear a bit // overwhelming. However, in addition to the basic plumbing shown in the example @@ -100,7 +111,7 @@ // To create instances of Metrics and their vector versions, you need a suitable // …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, or HistogramOpts. // -// Custom Collectors and constant Metrics +// # Custom Collectors and constant Metrics // // While you could create your own implementations of Metric, most likely you // will only ever implement the Collector interface on your own. At a first @@ -141,7 +152,7 @@ // a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting // shortcuts. // -// Advanced Uses of the Registry +// # Advanced Uses of the Registry // // While MustRegister is the by far most common way of registering a Collector, // sometimes you might want to handle the errors the registration might cause. @@ -176,23 +187,23 @@ // NewProcessCollector). With a custom registry, you are in control and decide // yourself about the Collectors to register. // -// HTTP Exposition +// # HTTP Exposition // // The Registry implements the Gatherer interface. The caller of the Gather // method can then expose the gathered metrics in some way. Usually, the metrics // are served via HTTP on the /metrics endpoint. That's happening in the example // above. The tools to expose metrics via HTTP are in the promhttp sub-package. // -// Pushing to the Pushgateway +// # Pushing to the Pushgateway // // Function for pushing to the Pushgateway can be found in the push sub-package. // -// Graphite Bridge +// # Graphite Bridge // // Functions and examples to push metrics from a Gatherer to Graphite can be // found in the graphite sub-package. // -// Other Means of Exposition +// # Other Means of Exposition // // More ways of exposing metrics can easily be added by following the approaches // of the existing implementations. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go index bd0733d6a..21271a5bb 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go @@ -210,7 +210,8 @@ func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { // 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) +// +// myVec.WithLabelValues("404", "GET").Add(42) func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge { g, err := v.GetMetricWithLabelValues(lvs...) if err != nil { @@ -221,7 +222,8 @@ func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge { // 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) +// +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42) func (v *GaugeVec) With(labels Labels) Gauge { g, err := v.GetMetricWith(labels) if err != nil { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go b/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go new file mode 100644 index 000000000..614fd61be --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/get_pid.go @@ -0,0 +1,26 @@ +// Copyright 2015 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. + +//go:build !js || wasm +// +build !js wasm + +package prometheus + +import "os" + +func getPIDFn() func() (int, error) { + pid := os.Getpid() + return func() (int, error) { + return pid, nil + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go b/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go new file mode 100644 index 000000000..eaf8059ee --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/get_pid_gopherjs.go @@ -0,0 +1,23 @@ +// Copyright 2015 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. + +//go:build js && !wasm +// +build js,!wasm + +package prometheus + +func getPIDFn() func() (int, error) { + return func() (int, error) { + return 1, nil + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go index 08195b410..ad9a71a5e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector.go @@ -19,6 +19,10 @@ import ( "time" ) +// goRuntimeMemStats provides the metrics initially provided by runtime.ReadMemStats. +// From Go 1.17 those similar (and better) statistics are provided by runtime/metrics, so +// while eval closure works on runtime.MemStats, the struct from Go 1.17+ is +// populated using runtime/metrics. func goRuntimeMemStats() memStatsMetrics { return memStatsMetrics{ { @@ -197,14 +201,6 @@ func goRuntimeMemStats() memStatsMetrics { ), eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) }, valType: GaugeValue, - }, { - desc: NewDesc( - memstatNamespace("gc_cpu_fraction"), - "The fraction of this program's available CPU time used by the GC since the program started.", - nil, nil, - ), - eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction }, - valType: GaugeValue, }, } } @@ -232,7 +228,7 @@ func newBaseGoCollector() baseGoCollector { "A summary of the pause duration of garbage collection cycles.", nil, nil), gcLastTimeDesc: NewDesc( - memstatNamespace("last_gc_time_seconds"), + "go_memstats_last_gc_time_seconds", "Number of seconds since 1970 of last garbage collection.", nil, nil), goInfoDesc: NewDesc( @@ -254,8 +250,9 @@ func (c *baseGoCollector) Describe(ch chan<- *Desc) { // Collect returns the current state of all metrics of the collector. func (c *baseGoCollector) Collect(ch chan<- Metric) { ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine())) - n, _ := runtime.ThreadCreateProfile(nil) - ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n)) + + n := getRuntimeNumThreads() + ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, n) var stats debug.GCStats stats.PauseQuantiles = make([]time.Duration, 5) @@ -268,7 +265,6 @@ func (c *baseGoCollector) Collect(ch chan<- Metric) { quantiles[0.0] = stats.PauseQuantiles[0].Seconds() ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles) ch <- MustNewConstMetric(c.gcLastTimeDesc, GaugeValue, float64(stats.LastGC.UnixNano())/1e9) - ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go index 24526131e..897a6e906 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go116.go @@ -40,13 +40,28 @@ type goCollector struct { // // Deprecated: Use collectors.NewGoCollector instead. func NewGoCollector() Collector { + msMetrics := goRuntimeMemStats() + msMetrics = append(msMetrics, struct { + desc *Desc + eval func(*runtime.MemStats) float64 + valType ValueType + }{ + // This metric is omitted in Go1.17+, see https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034 + desc: NewDesc( + memstatNamespace("gc_cpu_fraction"), + "The fraction of this program's available CPU time used by the GC since the program started.", + nil, nil, + ), + eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction }, + valType: GaugeValue, + }) return &goCollector{ base: newBaseGoCollector(), msLast: &runtime.MemStats{}, msRead: runtime.ReadMemStats, msMaxWait: time.Second, msMaxAge: 5 * time.Minute, - msMetrics: goRuntimeMemStats(), + msMetrics: msMetrics, } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go similarity index 53% rename from vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go rename to vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go index d43bdcdda..3a2d55e84 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_go117.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go @@ -25,10 +25,72 @@ import ( //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. "github.com/golang/protobuf/proto" - "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/client_golang/prometheus/internal" +) + +const ( + // constants for strings referenced more than once. + goGCHeapTinyAllocsObjects = "/gc/heap/tiny/allocs:objects" + goGCHeapAllocsObjects = "/gc/heap/allocs:objects" + goGCHeapFreesObjects = "/gc/heap/frees:objects" + goGCHeapFreesBytes = "/gc/heap/frees:bytes" + goGCHeapAllocsBytes = "/gc/heap/allocs:bytes" + goGCHeapObjects = "/gc/heap/objects:objects" + goGCHeapGoalBytes = "/gc/heap/goal:bytes" + goMemoryClassesTotalBytes = "/memory/classes/total:bytes" + goMemoryClassesHeapObjectsBytes = "/memory/classes/heap/objects:bytes" + goMemoryClassesHeapUnusedBytes = "/memory/classes/heap/unused:bytes" + goMemoryClassesHeapReleasedBytes = "/memory/classes/heap/released:bytes" + goMemoryClassesHeapFreeBytes = "/memory/classes/heap/free:bytes" + goMemoryClassesHeapStacksBytes = "/memory/classes/heap/stacks:bytes" + goMemoryClassesOSStacksBytes = "/memory/classes/os-stacks:bytes" + goMemoryClassesMetadataMSpanInuseBytes = "/memory/classes/metadata/mspan/inuse:bytes" + goMemoryClassesMetadataMSPanFreeBytes = "/memory/classes/metadata/mspan/free:bytes" + goMemoryClassesMetadataMCacheInuseBytes = "/memory/classes/metadata/mcache/inuse:bytes" + goMemoryClassesMetadataMCacheFreeBytes = "/memory/classes/metadata/mcache/free:bytes" + goMemoryClassesProfilingBucketsBytes = "/memory/classes/profiling/buckets:bytes" + goMemoryClassesMetadataOtherBytes = "/memory/classes/metadata/other:bytes" + goMemoryClassesOtherBytes = "/memory/classes/other:bytes" ) +// rmNamesForMemStatsMetrics represents runtime/metrics names required to populate goRuntimeMemStats from like logic. +var rmNamesForMemStatsMetrics = []string{ + goGCHeapTinyAllocsObjects, + goGCHeapAllocsObjects, + goGCHeapFreesObjects, + goGCHeapAllocsBytes, + goGCHeapObjects, + goGCHeapGoalBytes, + goMemoryClassesTotalBytes, + goMemoryClassesHeapObjectsBytes, + goMemoryClassesHeapUnusedBytes, + goMemoryClassesHeapReleasedBytes, + goMemoryClassesHeapFreeBytes, + goMemoryClassesHeapStacksBytes, + goMemoryClassesOSStacksBytes, + goMemoryClassesMetadataMSpanInuseBytes, + goMemoryClassesMetadataMSPanFreeBytes, + goMemoryClassesMetadataMCacheInuseBytes, + goMemoryClassesMetadataMCacheFreeBytes, + goMemoryClassesProfilingBucketsBytes, + goMemoryClassesMetadataOtherBytes, + goMemoryClassesOtherBytes, +} + +func bestEffortLookupRM(lookup []string) []metrics.Description { + ret := make([]metrics.Description, 0, len(lookup)) + for _, rm := range metrics.All() { + for _, m := range lookup { + if m == rm.Name { + ret = append(ret, rm) + } + } + } + return ret +} + type goCollector struct { base baseGoCollector @@ -36,70 +98,124 @@ type goCollector struct { // snapshot is always produced by Collect. mu sync.Mutex - // rm... fields all pertain to the runtime/metrics package. - rmSampleBuf []metrics.Sample - rmSampleMap map[string]*metrics.Sample - rmMetrics []collectorMetric + // Contains all samples that has to retrieved from runtime/metrics (not all of them will be exposed). + sampleBuf []metrics.Sample + // sampleMap allows lookup for MemStats metrics and runtime/metrics histograms for exact sums. + sampleMap map[string]*metrics.Sample + + // rmExposedMetrics represents all runtime/metrics package metrics + // that were configured to be exposed. + rmExposedMetrics []collectorMetric + rmExactSumMapForHist map[string]string // With Go 1.17, the runtime/metrics package was introduced. // From that point on, metric names produced by the runtime/metrics // package could be generated from runtime/metrics names. However, // these differ from the old names for the same values. // - // This field exist to export the same values under the old names + // This field exists to export the same values under the old names // as well. - msMetrics memStatsMetrics + msMetrics memStatsMetrics + msMetricsEnabled bool +} + +type rmMetricDesc struct { + metrics.Description +} + +func matchRuntimeMetricsRules(rules []internal.GoCollectorRule) []rmMetricDesc { + var descs []rmMetricDesc + for _, d := range metrics.All() { + var ( + deny = true + desc rmMetricDesc + ) + + for _, r := range rules { + if !r.Matcher.MatchString(d.Name) { + continue + } + deny = r.Deny + } + if deny { + continue + } + + desc.Description = d + descs = append(descs, desc) + } + return descs +} + +func defaultGoCollectorOptions() internal.GoCollectorOptions { + return internal.GoCollectorOptions{ + RuntimeMetricSumForHist: map[string]string{ + "/gc/heap/allocs-by-size:bytes": goGCHeapAllocsBytes, + "/gc/heap/frees-by-size:bytes": goGCHeapFreesBytes, + }, + RuntimeMetricRules: []internal.GoCollectorRule{ + //{Matcher: regexp.MustCompile("")}, + }, + } } // NewGoCollector is the obsolete version of collectors.NewGoCollector. // See there for documentation. // // Deprecated: Use collectors.NewGoCollector instead. -func NewGoCollector() Collector { - descriptions := metrics.All() +func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector { + opt := defaultGoCollectorOptions() + for _, o := range opts { + o(&opt) + } + + exposedDescriptions := matchRuntimeMetricsRules(opt.RuntimeMetricRules) // Collect all histogram samples so that we can get their buckets. // The API guarantees that the buckets are always fixed for the lifetime // of the process. var histograms []metrics.Sample - for _, d := range descriptions { + for _, d := range exposedDescriptions { if d.Kind == metrics.KindFloat64Histogram { histograms = append(histograms, metrics.Sample{Name: d.Name}) } } - metrics.Read(histograms) + + if len(histograms) > 0 { + metrics.Read(histograms) + } + bucketsMap := make(map[string][]float64) for i := range histograms { bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets } - // Generate a Desc and ValueType for each runtime/metrics metric. - metricSet := make([]collectorMetric, 0, len(descriptions)) - sampleBuf := make([]metrics.Sample, 0, len(descriptions)) - sampleMap := make(map[string]*metrics.Sample, len(descriptions)) - for i := range descriptions { - d := &descriptions[i] - namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(d) + // Generate a collector for each exposed runtime/metrics metric. + metricSet := make([]collectorMetric, 0, len(exposedDescriptions)) + // SampleBuf is used for reading from runtime/metrics. + // We are assuming the largest case to have stable pointers for sampleMap purposes. + sampleBuf := make([]metrics.Sample, 0, len(exposedDescriptions)+len(opt.RuntimeMetricSumForHist)+len(rmNamesForMemStatsMetrics)) + sampleMap := make(map[string]*metrics.Sample, len(exposedDescriptions)) + for _, d := range exposedDescriptions { + namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(&d.Description) if !ok { // Just ignore this metric; we can't do anything with it here. // If a user decides to use the latest version of Go, we don't want - // to fail here. This condition is tested elsewhere. + // to fail here. This condition is tested in TestExpectedRuntimeMetrics. continue } - // Set up sample buffer for reading, and a map - // for quick lookup of sample values. sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name}) sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1] var m collectorMetric if d.Kind == metrics.KindFloat64Histogram { - _, hasSum := rmExactSumMap[d.Name] + _, hasSum := opt.RuntimeMetricSumForHist[d.Name] unit := d.Name[strings.IndexRune(d.Name, ':')+1:] m = newBatchHistogram( NewDesc( BuildFQName(namespace, subsystem, name), - d.Description, + d.Description.Description, nil, nil, ), @@ -111,24 +227,61 @@ func NewGoCollector() Collector { Namespace: namespace, Subsystem: subsystem, Name: name, - Help: d.Description, - }) + Help: d.Description.Description, + }, + ) } else { m = NewGauge(GaugeOpts{ Namespace: namespace, Subsystem: subsystem, Name: name, - Help: d.Description, + Help: d.Description.Description, }) } metricSet = append(metricSet, m) } + + // Add exact sum metrics to sampleBuf if not added before. + for _, h := range histograms { + sumMetric, ok := opt.RuntimeMetricSumForHist[h.Name] + if !ok { + continue + } + + if _, ok := sampleMap[sumMetric]; ok { + continue + } + sampleBuf = append(sampleBuf, metrics.Sample{Name: sumMetric}) + sampleMap[sumMetric] = &sampleBuf[len(sampleBuf)-1] + } + + var ( + msMetrics memStatsMetrics + msDescriptions []metrics.Description + ) + + if !opt.DisableMemStatsLikeMetrics { + msMetrics = goRuntimeMemStats() + msDescriptions = bestEffortLookupRM(rmNamesForMemStatsMetrics) + + // Check if metric was not exposed before and if not, add to sampleBuf. + for _, mdDesc := range msDescriptions { + if _, ok := sampleMap[mdDesc.Name]; ok { + continue + } + sampleBuf = append(sampleBuf, metrics.Sample{Name: mdDesc.Name}) + sampleMap[mdDesc.Name] = &sampleBuf[len(sampleBuf)-1] + } + } + return &goCollector{ - base: newBaseGoCollector(), - rmSampleBuf: sampleBuf, - rmSampleMap: sampleMap, - rmMetrics: metricSet, - msMetrics: goRuntimeMemStats(), + base: newBaseGoCollector(), + sampleBuf: sampleBuf, + sampleMap: sampleMap, + rmExposedMetrics: metricSet, + rmExactSumMapForHist: opt.RuntimeMetricSumForHist, + msMetrics: msMetrics, + msMetricsEnabled: !opt.DisableMemStatsLikeMetrics, } } @@ -138,7 +291,7 @@ func (c *goCollector) Describe(ch chan<- *Desc) { for _, i := range c.msMetrics { ch <- i.desc } - for _, m := range c.rmMetrics { + for _, m := range c.rmExposedMetrics { ch <- m.Desc() } } @@ -148,8 +301,12 @@ func (c *goCollector) Collect(ch chan<- Metric) { // Collect base non-memory metrics. c.base.Collect(ch) + if len(c.sampleBuf) == 0 { + return + } + // Collect must be thread-safe, so prevent concurrent use of - // rmSampleBuf. Just read into rmSampleBuf but write all the data + // sampleBuf elements. Just read into sampleBuf but write all the data // we get into our Metrics or MemStats. // // This lock also ensures that the Metrics we send out are all from @@ -164,14 +321,17 @@ func (c *goCollector) Collect(ch chan<- Metric) { defer c.mu.Unlock() // Populate runtime/metrics sample buffer. - metrics.Read(c.rmSampleBuf) + metrics.Read(c.sampleBuf) + + // Collect all our runtime/metrics user chose to expose from sampleBuf (if any). + for i, metric := range c.rmExposedMetrics { + // We created samples for exposed metrics first in order, so indexes match. + sample := c.sampleBuf[i] - // Update all our metrics from rmSampleBuf. - for i, sample := range c.rmSampleBuf { // N.B. switch on concrete type because it's significantly more efficient // than checking for the Counter and Gauge interface implementations. In // this case, we control all the types here. - switch m := c.rmMetrics[i].(type) { + switch m := metric.(type) { case *counter: // Guard against decreases. This should never happen, but a failure // to do so will result in a panic, which is a harsh consequence for @@ -191,12 +351,15 @@ func (c *goCollector) Collect(ch chan<- Metric) { panic("unexpected metric type") } } - // ms is a dummy MemStats that we populate ourselves so that we can - // populate the old metrics from it. - var ms runtime.MemStats - memStatsFromRM(&ms, c.rmSampleMap) - for _, i := range c.msMetrics { - ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms)) + + if c.msMetricsEnabled { + // ms is a dummy MemStats that we populate ourselves so that we can + // populate the old metrics from it if goMemStatsCollection is enabled. + var ms runtime.MemStats + memStatsFromRM(&ms, c.sampleMap) + for _, i := range c.msMetrics { + ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms)) + } } } @@ -224,11 +387,6 @@ func unwrapScalarRMValue(v metrics.Value) float64 { } } -var rmExactSumMap = map[string]string{ - "/gc/heap/allocs-by-size:bytes": "/gc/heap/allocs:bytes", - "/gc/heap/frees-by-size:bytes": "/gc/heap/frees:bytes", -} - // exactSumFor takes a runtime/metrics metric name (that is assumed to // be of kind KindFloat64Histogram) and returns its exact sum and whether // its exact sum exists. @@ -236,11 +394,11 @@ var rmExactSumMap = map[string]string{ // The runtime/metrics API for histograms doesn't currently expose exact // sums, but some of the other metrics are in fact exact sums of histograms. func (c *goCollector) exactSumFor(rmName string) float64 { - sumName, ok := rmExactSumMap[rmName] + sumName, ok := c.rmExactSumMapForHist[rmName] if !ok { return 0 } - s, ok := c.rmSampleMap[sumName] + s, ok := c.sampleMap[sumName] if !ok { return 0 } @@ -261,35 +419,30 @@ func memStatsFromRM(ms *runtime.MemStats, rm map[string]*metrics.Sample) { // while having Mallocs - Frees still represent a live object count. // Unfortunately, MemStats doesn't actually export a large allocation count, // so it's impossible to pull this number out directly. - tinyAllocs := lookupOrZero("/gc/heap/tiny/allocs:objects") - ms.Mallocs = lookupOrZero("/gc/heap/allocs:objects") + tinyAllocs - ms.Frees = lookupOrZero("/gc/heap/frees:objects") + tinyAllocs + tinyAllocs := lookupOrZero(goGCHeapTinyAllocsObjects) + ms.Mallocs = lookupOrZero(goGCHeapAllocsObjects) + tinyAllocs + ms.Frees = lookupOrZero(goGCHeapFreesObjects) + tinyAllocs - ms.TotalAlloc = lookupOrZero("/gc/heap/allocs:bytes") - ms.Sys = lookupOrZero("/memory/classes/total:bytes") + ms.TotalAlloc = lookupOrZero(goGCHeapAllocsBytes) + ms.Sys = lookupOrZero(goMemoryClassesTotalBytes) ms.Lookups = 0 // Already always zero. - ms.HeapAlloc = lookupOrZero("/memory/classes/heap/objects:bytes") + ms.HeapAlloc = lookupOrZero(goMemoryClassesHeapObjectsBytes) ms.Alloc = ms.HeapAlloc - ms.HeapInuse = ms.HeapAlloc + lookupOrZero("/memory/classes/heap/unused:bytes") - ms.HeapReleased = lookupOrZero("/memory/classes/heap/released:bytes") - ms.HeapIdle = ms.HeapReleased + lookupOrZero("/memory/classes/heap/free:bytes") + ms.HeapInuse = ms.HeapAlloc + lookupOrZero(goMemoryClassesHeapUnusedBytes) + ms.HeapReleased = lookupOrZero(goMemoryClassesHeapReleasedBytes) + ms.HeapIdle = ms.HeapReleased + lookupOrZero(goMemoryClassesHeapFreeBytes) ms.HeapSys = ms.HeapInuse + ms.HeapIdle - ms.HeapObjects = lookupOrZero("/gc/heap/objects:objects") - ms.StackInuse = lookupOrZero("/memory/classes/heap/stacks:bytes") - ms.StackSys = ms.StackInuse + lookupOrZero("/memory/classes/os-stacks:bytes") - ms.MSpanInuse = lookupOrZero("/memory/classes/metadata/mspan/inuse:bytes") - ms.MSpanSys = ms.MSpanInuse + lookupOrZero("/memory/classes/metadata/mspan/free:bytes") - ms.MCacheInuse = lookupOrZero("/memory/classes/metadata/mcache/inuse:bytes") - ms.MCacheSys = ms.MCacheInuse + lookupOrZero("/memory/classes/metadata/mcache/free:bytes") - ms.BuckHashSys = lookupOrZero("/memory/classes/profiling/buckets:bytes") - ms.GCSys = lookupOrZero("/memory/classes/metadata/other:bytes") - ms.OtherSys = lookupOrZero("/memory/classes/other:bytes") - ms.NextGC = lookupOrZero("/gc/heap/goal:bytes") - - // N.B. LastGC is omitted because runtime.GCStats already has this. - // See https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034 - // for more details. - ms.LastGC = 0 + ms.HeapObjects = lookupOrZero(goGCHeapObjects) + ms.StackInuse = lookupOrZero(goMemoryClassesHeapStacksBytes) + ms.StackSys = ms.StackInuse + lookupOrZero(goMemoryClassesOSStacksBytes) + ms.MSpanInuse = lookupOrZero(goMemoryClassesMetadataMSpanInuseBytes) + ms.MSpanSys = ms.MSpanInuse + lookupOrZero(goMemoryClassesMetadataMSPanFreeBytes) + ms.MCacheInuse = lookupOrZero(goMemoryClassesMetadataMCacheInuseBytes) + ms.MCacheSys = ms.MCacheInuse + lookupOrZero(goMemoryClassesMetadataMCacheFreeBytes) + ms.BuckHashSys = lookupOrZero(goMemoryClassesProfilingBucketsBytes) + ms.GCSys = lookupOrZero(goMemoryClassesMetadataOtherBytes) + ms.OtherSys = lookupOrZero(goMemoryClassesOtherBytes) + ms.NextGC = lookupOrZero(goGCHeapGoalBytes) // N.B. GCCPUFraction is intentionally omitted. This metric is not useful, // and often misleading due to the fact that it's an average over the lifetime @@ -324,6 +477,11 @@ type batchHistogram struct { // buckets must always be from the runtime/metrics package, following // the same conventions. func newBatchHistogram(desc *Desc, buckets []float64, hasSum bool) *batchHistogram { + // We need to remove -Inf values. runtime/metrics keeps them around. + // But -Inf bucket should not be allowed for prometheus histograms. + if buckets[0] == math.Inf(-1) { + buckets = buckets[1:] + } h := &batchHistogram{ desc: desc, buckets: buckets, @@ -382,8 +540,10 @@ func (h *batchHistogram) Write(out *dto.Metric) error { for i, count := range h.counts { totalCount += count if !h.hasSum { - // N.B. This computed sum is an underestimate. - sum += h.buckets[i] * float64(count) + if count != 0 { + // N.B. This computed sum is an underestimate. + sum += h.buckets[i] * float64(count) + } } // Skip the +Inf bucket, but only for the bucket list. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index 893802fd6..4c873a01c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -28,19 +28,216 @@ import ( dto "github.com/prometheus/client_model/go" ) +// nativeHistogramBounds for the frac of observed values. Only relevant for +// schema > 0. The position in the slice is the schema. (0 is never used, just +// here for convenience of using the schema directly as the index.) +// +// TODO(beorn7): Currently, we do a binary search into these slices. There are +// ways to turn it into a small number of simple array lookups. It probably only +// matters for schema 5 and beyond, but should be investigated. See this comment +// as a starting point: +// https://github.com/open-telemetry/opentelemetry-specification/issues/1776#issuecomment-870164310 +var nativeHistogramBounds = [][]float64{ + // Schema "0": + {0.5}, + // Schema 1: + {0.5, 0.7071067811865475}, + // Schema 2: + {0.5, 0.5946035575013605, 0.7071067811865475, 0.8408964152537144}, + // Schema 3: + { + 0.5, 0.5452538663326288, 0.5946035575013605, 0.6484197773255048, + 0.7071067811865475, 0.7711054127039704, 0.8408964152537144, 0.9170040432046711, + }, + // Schema 4: + { + 0.5, 0.5221368912137069, 0.5452538663326288, 0.5693943173783458, + 0.5946035575013605, 0.620928906036742, 0.6484197773255048, 0.6771277734684463, + 0.7071067811865475, 0.7384130729697496, 0.7711054127039704, 0.805245165974627, + 0.8408964152537144, 0.8781260801866495, 0.9170040432046711, 0.9576032806985735, + }, + // Schema 5: + { + 0.5, 0.5109485743270583, 0.5221368912137069, 0.5335702003384117, + 0.5452538663326288, 0.5571933712979462, 0.5693943173783458, 0.5818624293887887, + 0.5946035575013605, 0.6076236799902344, 0.620928906036742, 0.6345254785958666, + 0.6484197773255048, 0.6626183215798706, 0.6771277734684463, 0.6919549409819159, + 0.7071067811865475, 0.7225904034885232, 0.7384130729697496, 0.7545822137967112, + 0.7711054127039704, 0.7879904225539431, 0.805245165974627, 0.8228777390769823, + 0.8408964152537144, 0.8593096490612387, 0.8781260801866495, 0.8973545375015533, + 0.9170040432046711, 0.9370838170551498, 0.9576032806985735, 0.9785720620876999, + }, + // Schema 6: + { + 0.5, 0.5054446430258502, 0.5109485743270583, 0.5165124395106142, + 0.5221368912137069, 0.5278225891802786, 0.5335702003384117, 0.5393803988785598, + 0.5452538663326288, 0.5511912916539204, 0.5571933712979462, 0.5632608093041209, + 0.5693943173783458, 0.5755946149764913, 0.5818624293887887, 0.5881984958251406, + 0.5946035575013605, 0.6010783657263515, 0.6076236799902344, 0.6142402680534349, + 0.620928906036742, 0.6276903785123455, 0.6345254785958666, 0.6414350080393891, + 0.6484197773255048, 0.6554806057623822, 0.6626183215798706, 0.6698337620266515, + 0.6771277734684463, 0.6845012114872953, 0.6919549409819159, 0.6994898362691555, + 0.7071067811865475, 0.7148066691959849, 0.7225904034885232, 0.7304588970903234, + 0.7384130729697496, 0.7464538641456323, 0.7545822137967112, 0.762799075372269, + 0.7711054127039704, 0.7795022001189185, 0.7879904225539431, 0.7965710756711334, + 0.805245165974627, 0.8140137109286738, 0.8228777390769823, 0.8318382901633681, + 0.8408964152537144, 0.8500531768592616, 0.8593096490612387, 0.8686669176368529, + 0.8781260801866495, 0.8876882462632604, 0.8973545375015533, 0.9071260877501991, + 0.9170040432046711, 0.9269895625416926, 0.9370838170551498, 0.9472879907934827, + 0.9576032806985735, 0.9680308967461471, 0.9785720620876999, 0.9892280131939752, + }, + // Schema 7: + { + 0.5, 0.5027149505564014, 0.5054446430258502, 0.5081891574554764, + 0.5109485743270583, 0.5137229745593818, 0.5165124395106142, 0.5193170509806894, + 0.5221368912137069, 0.5249720429003435, 0.5278225891802786, 0.5306886136446309, + 0.5335702003384117, 0.5364674337629877, 0.5393803988785598, 0.5423091811066545, + 0.5452538663326288, 0.5482145409081883, 0.5511912916539204, 0.5541842058618393, + 0.5571933712979462, 0.5602188762048033, 0.5632608093041209, 0.5663192597993595, + 0.5693943173783458, 0.572486072215902, 0.5755946149764913, 0.5787200368168754, + 0.5818624293887887, 0.585021884841625, 0.5881984958251406, 0.5913923554921704, + 0.5946035575013605, 0.5978321960199137, 0.6010783657263515, 0.6043421618132907, + 0.6076236799902344, 0.6109230164863786, 0.6142402680534349, 0.6175755319684665, + 0.620928906036742, 0.6243004885946023, 0.6276903785123455, 0.6310986751971253, + 0.6345254785958666, 0.637970889198196, 0.6414350080393891, 0.6449179367033329, + 0.6484197773255048, 0.6519406325959679, 0.6554806057623822, 0.659039800633032, + 0.6626183215798706, 0.6662162735415805, 0.6698337620266515, 0.6734708931164728, + 0.6771277734684463, 0.6808045103191123, 0.6845012114872953, 0.688217985377265, + 0.6919549409819159, 0.6957121878859629, 0.6994898362691555, 0.7032879969095076, + 0.7071067811865475, 0.7109463010845827, 0.7148066691959849, 0.718687998724491, + 0.7225904034885232, 0.7265139979245261, 0.7304588970903234, 0.7344252166684908, + 0.7384130729697496, 0.7424225829363761, 0.7464538641456323, 0.7505070348132126, + 0.7545822137967112, 0.7586795205991071, 0.762799075372269, 0.7669409989204777, + 0.7711054127039704, 0.7752924388424999, 0.7795022001189185, 0.7837348199827764, + 0.7879904225539431, 0.7922691326262467, 0.7965710756711334, 0.8008963778413465, + 0.805245165974627, 0.8096175675974316, 0.8140137109286738, 0.8184337248834821, + 0.8228777390769823, 0.8273458838280969, 0.8318382901633681, 0.8363550898207981, + 0.8408964152537144, 0.8454623996346523, 0.8500531768592616, 0.8546688815502312, + 0.8593096490612387, 0.8639756154809185, 0.8686669176368529, 0.8733836930995842, + 0.8781260801866495, 0.8828942179666361, 0.8876882462632604, 0.8925083056594671, + 0.8973545375015533, 0.9022270839033115, 0.9071260877501991, 0.9120516927035263, + 0.9170040432046711, 0.9219832844793128, 0.9269895625416926, 0.9320230241988943, + 0.9370838170551498, 0.9421720895161669, 0.9472879907934827, 0.9524316709088368, + 0.9576032806985735, 0.9628029718180622, 0.9680308967461471, 0.9732872087896164, + 0.9785720620876999, 0.9838856116165875, 0.9892280131939752, 0.9945994234836328, + }, + // Schema 8: + { + 0.5, 0.5013556375251013, 0.5027149505564014, 0.5040779490592088, + 0.5054446430258502, 0.5068150424757447, 0.5081891574554764, 0.509566998038869, + 0.5109485743270583, 0.5123338964485679, 0.5137229745593818, 0.5151158188430205, + 0.5165124395106142, 0.5179128468009786, 0.5193170509806894, 0.520725062344158, + 0.5221368912137069, 0.5235525479396449, 0.5249720429003435, 0.526395386502313, + 0.5278225891802786, 0.5292536613972564, 0.5306886136446309, 0.5321274564422321, + 0.5335702003384117, 0.5350168559101208, 0.5364674337629877, 0.5379219445313954, + 0.5393803988785598, 0.5408428074966075, 0.5423091811066545, 0.5437795304588847, + 0.5452538663326288, 0.5467321995364429, 0.5482145409081883, 0.549700901315111, + 0.5511912916539204, 0.5526857228508706, 0.5541842058618393, 0.5556867516724088, + 0.5571933712979462, 0.5587040757836845, 0.5602188762048033, 0.5617377836665098, + 0.5632608093041209, 0.564787964283144, 0.5663192597993595, 0.5678547070789026, + 0.5693943173783458, 0.5709381019847808, 0.572486072215902, 0.5740382394200894, + 0.5755946149764913, 0.5771552102951081, 0.5787200368168754, 0.5802891060137493, + 0.5818624293887887, 0.5834400184762408, 0.585021884841625, 0.5866080400818185, + 0.5881984958251406, 0.5897932637314379, 0.5913923554921704, 0.5929957828304968, + 0.5946035575013605, 0.5962156912915756, 0.5978321960199137, 0.5994530835371903, + 0.6010783657263515, 0.6027080545025619, 0.6043421618132907, 0.6059806996384005, + 0.6076236799902344, 0.6092711149137041, 0.6109230164863786, 0.6125793968185725, + 0.6142402680534349, 0.6159056423670379, 0.6175755319684665, 0.6192499490999082, + 0.620928906036742, 0.622612415087629, 0.6243004885946023, 0.6259931389331581, + 0.6276903785123455, 0.6293922197748583, 0.6310986751971253, 0.6328097572894031, + 0.6345254785958666, 0.6362458516947014, 0.637970889198196, 0.6397006037528346, + 0.6414350080393891, 0.6431741147730128, 0.6449179367033329, 0.6466664866145447, + 0.6484197773255048, 0.6501778216898253, 0.6519406325959679, 0.6537082229673385, + 0.6554806057623822, 0.6572577939746774, 0.659039800633032, 0.6608266388015788, + 0.6626183215798706, 0.6644148621029772, 0.6662162735415805, 0.6680225691020727, + 0.6698337620266515, 0.6716498655934177, 0.6734708931164728, 0.6752968579460171, + 0.6771277734684463, 0.6789636531064505, 0.6808045103191123, 0.6826503586020058, + 0.6845012114872953, 0.6863570825438342, 0.688217985377265, 0.690083933630119, + 0.6919549409819159, 0.6938310211492645, 0.6957121878859629, 0.6975984549830999, + 0.6994898362691555, 0.7013863456101023, 0.7032879969095076, 0.7051948041086352, + 0.7071067811865475, 0.7090239421602076, 0.7109463010845827, 0.7128738720527471, + 0.7148066691959849, 0.7167447066838943, 0.718687998724491, 0.7206365595643126, + 0.7225904034885232, 0.7245495448210174, 0.7265139979245261, 0.7284837772007218, + 0.7304588970903234, 0.7324393720732029, 0.7344252166684908, 0.7364164454346837, + 0.7384130729697496, 0.7404151139112358, 0.7424225829363761, 0.7444354947621984, + 0.7464538641456323, 0.7484777058836176, 0.7505070348132126, 0.7525418658117031, + 0.7545822137967112, 0.7566280937263048, 0.7586795205991071, 0.7607365094544071, + 0.762799075372269, 0.7648672334736434, 0.7669409989204777, 0.7690203869158282, + 0.7711054127039704, 0.7731960915705107, 0.7752924388424999, 0.7773944698885442, + 0.7795022001189185, 0.7816156449856788, 0.7837348199827764, 0.7858597406461707, + 0.7879904225539431, 0.7901268813264122, 0.7922691326262467, 0.7944171921585818, + 0.7965710756711334, 0.7987307989543135, 0.8008963778413465, 0.8030678282083853, + 0.805245165974627, 0.8074284071024302, 0.8096175675974316, 0.8118126635086642, + 0.8140137109286738, 0.8162207259936375, 0.8184337248834821, 0.820652723822003, + 0.8228777390769823, 0.8251087869603088, 0.8273458838280969, 0.8295890460808079, + 0.8318382901633681, 0.8340936325652911, 0.8363550898207981, 0.8386226785089391, + 0.8408964152537144, 0.8431763167241966, 0.8454623996346523, 0.8477546807446661, + 0.8500531768592616, 0.8523579048290255, 0.8546688815502312, 0.8569861239649629, + 0.8593096490612387, 0.8616394738731368, 0.8639756154809185, 0.8663180910111553, + 0.8686669176368529, 0.871022112577578, 0.8733836930995842, 0.8757516765159389, + 0.8781260801866495, 0.8805069215187917, 0.8828942179666361, 0.8852879870317771, + 0.8876882462632604, 0.890095013257712, 0.8925083056594671, 0.8949281411607002, + 0.8973545375015533, 0.8997875124702672, 0.9022270839033115, 0.9046732696855155, + 0.9071260877501991, 0.909585556079304, 0.9120516927035263, 0.9145245157024483, + 0.9170040432046711, 0.9194902933879467, 0.9219832844793128, 0.9244830347552253, + 0.9269895625416926, 0.92950288621441, 0.9320230241988943, 0.9345499949706191, + 0.9370838170551498, 0.93962450902828, 0.9421720895161669, 0.9447265771954693, + 0.9472879907934827, 0.9498563490882775, 0.9524316709088368, 0.9550139751351947, + 0.9576032806985735, 0.9601996065815236, 0.9628029718180622, 0.9654133954938133, + 0.9680308967461471, 0.9706554947643201, 0.9732872087896164, 0.9759260581154889, + 0.9785720620876999, 0.9812252401044634, 0.9838856116165875, 0.9865531961276168, + 0.9892280131939752, 0.9919100824251095, 0.9945994234836328, 0.9972960560854698, + }, +} + +// The nativeHistogramBounds above can be generated with the code below. +// +// TODO(beorn7): It's tempting to actually use `go generate` to generate the +// code above. However, this could lead to slightly different numbers on +// different architectures. We still need to come to terms if we are fine with +// that, or if we might prefer to specify precise numbers in the standard. +// +// var nativeHistogramBounds [][]float64 = make([][]float64, 9) +// +// func init() { +// // Populate nativeHistogramBounds. +// numBuckets := 1 +// for i := range nativeHistogramBounds { +// bounds := []float64{0.5} +// factor := math.Exp2(math.Exp2(float64(-i))) +// for j := 0; j < numBuckets-1; j++ { +// var bound float64 +// if (j+1)%2 == 0 { +// // Use previously calculated value for increased precision. +// bound = nativeHistogramBounds[i-1][j/2+1] +// } else { +// bound = bounds[j] * factor +// } +// bounds = append(bounds, bound) +// } +// numBuckets *= 2 +// nativeHistogramBounds[i] = bounds +// } +// } + // A Histogram counts individual observations from an event or sample stream in -// configurable buckets. Similar to a summary, it also provides a sum of -// observations and an observation count. +// configurable static buckets (or in dynamic sparse buckets as part of the +// experimental Native Histograms, see below for more details). Similar to a +// Summary, it also provides a sum of observations and an observation count. // // On the Prometheus server, quantiles can be calculated from a Histogram using -// the histogram_quantile function in the query language. +// the histogram_quantile PromQL function. +// +// Note that Histograms, in contrast to Summaries, can be aggregated in PromQL +// (see the documentation for detailed procedures). However, Histograms require +// the user to pre-define suitable buckets, and they are in general less +// accurate. (Both problems are addressed by the experimental Native +// Histograms. To use them, configure a NativeHistogramBucketFactor in the +// HistogramOpts. They also require a Prometheus server v2.40+ with the +// corresponding feature flag enabled.) // -// Note that Histograms, in contrast to Summaries, can be aggregated with the -// Prometheus query language (see the documentation for detailed -// procedures). However, Histograms require the user to pre-define suitable -// buckets, and they are in general less accurate. The Observe method of a -// Histogram has a very low performance overhead in comparison with the Observe -// method of a Summary. +// The Observe method of a Histogram has a very low performance overhead in +// comparison with the Observe method of a Summary. // // To create Histogram instances, use NewHistogram. type Histogram interface { @@ -50,7 +247,8 @@ type Histogram interface { // Observe adds a single observation to the histogram. Observations are // usually positive or zero. Negative observations are accepted but // prevent current versions of Prometheus from properly detecting - // counter resets in the sum of observations. See + // counter resets in the sum of observations. (The experimental Native + // Histograms handle negative observations properly.) See // https://prometheus.io/docs/practices/histograms/#count-and-sum-of-observations // for details. Observe(float64) @@ -64,18 +262,28 @@ const bucketLabel = "le" // tailored to broadly measure the response time (in seconds) of a network // service. Most likely, however, you will be required to define buckets // customized to your use case. -var ( - DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10} +var DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10} - errBucketLabelNotAllowed = fmt.Errorf( - "%q is not allowed as label name in histograms", bucketLabel, - ) +// DefNativeHistogramZeroThreshold is the default value for +// NativeHistogramZeroThreshold in the HistogramOpts. +// +// The value is 2^-128 (or 0.5*2^-127 in the actual IEEE 754 representation), +// which is a bucket boundary at all possible resolutions. +const DefNativeHistogramZeroThreshold = 2.938735877055719e-39 + +// NativeHistogramZeroThresholdZero can be used as NativeHistogramZeroThreshold +// in the HistogramOpts to create a zero bucket of width zero, i.e. a zero +// bucket that only receives observations of precisely zero. +const NativeHistogramZeroThresholdZero = -1 + +var errBucketLabelNotAllowed = fmt.Errorf( + "%q is not allowed as label name in histograms", bucketLabel, ) -// LinearBuckets creates 'count' buckets, each 'width' wide, where the lowest -// bucket has an upper bound of 'start'. The final +Inf bucket is not counted -// and not included in the returned slice. The returned slice is meant to be -// used for the Buckets field of HistogramOpts. +// LinearBuckets creates 'count' regular buckets, each 'width' wide, where the +// lowest bucket has an upper bound of 'start'. The final +Inf bucket is not +// counted and not included in the returned slice. The returned slice is meant +// to be used for the Buckets field of HistogramOpts. // // The function panics if 'count' is zero or negative. func LinearBuckets(start, width float64, count int) []float64 { @@ -90,11 +298,11 @@ func LinearBuckets(start, width float64, count int) []float64 { return buckets } -// ExponentialBuckets creates 'count' buckets, where the lowest bucket has an -// upper bound of 'start' and each following bucket's upper bound is 'factor' -// times the previous bucket's upper bound. The final +Inf bucket is not counted -// and not included in the returned slice. The returned slice is meant to be -// used for the Buckets field of HistogramOpts. +// ExponentialBuckets creates 'count' regular buckets, where the lowest bucket +// has an upper bound of 'start' and each following bucket's upper bound is +// 'factor' times the previous bucket's upper bound. The final +Inf bucket is +// not counted and not included in the returned slice. The returned slice is +// meant to be used for the Buckets field of HistogramOpts. // // The function panics if 'count' is 0 or negative, if 'start' is 0 or negative, // or if 'factor' is less than or equal 1. @@ -180,8 +388,85 @@ type HistogramOpts struct { // element in the slice is the upper inclusive bound of a bucket. The // values must be sorted in strictly increasing order. There is no need // to add a highest bucket with +Inf bound, it will be added - // implicitly. The default value is DefBuckets. + // implicitly. If Buckets is left as nil or set to a slice of length + // zero, it is replaced by default buckets. The default buckets are + // DefBuckets if no buckets for a native histogram (see below) are used, + // otherwise the default is no buckets. (In other words, if you want to + // use both reguler buckets and buckets for a native histogram, you have + // to define the regular buckets here explicitly.) Buckets []float64 + + // If NativeHistogramBucketFactor is greater than one, so-called sparse + // buckets are used (in addition to the regular buckets, if defined + // above). A Histogram with sparse buckets will be ingested as a Native + // Histogram by a Prometheus server with that feature enabled (requires + // Prometheus v2.40+). Sparse buckets are exponential buckets covering + // the whole float64 range (with the exception of the “zero” bucket, see + // SparseBucketsZeroThreshold below). From any one bucket to the next, + // the width of the bucket grows by a constant + // factor. NativeHistogramBucketFactor provides an upper bound for this + // factor (exception see below). The smaller + // NativeHistogramBucketFactor, the more buckets will be used and thus + // the more costly the histogram will become. A generally good trade-off + // between cost and accuracy is a value of 1.1 (each bucket is at most + // 10% wider than the previous one), which will result in each power of + // two divided into 8 buckets (e.g. there will be 8 buckets between 1 + // and 2, same as between 2 and 4, and 4 and 8, etc.). + // + // Details about the actually used factor: The factor is calculated as + // 2^(2^n), where n is an integer number between (and including) -8 and + // 4. n is chosen so that the resulting factor is the largest that is + // still smaller or equal to NativeHistogramBucketFactor. Note that the + // smallest possible factor is therefore approx. 1.00271 (i.e. 2^(2^-8) + // ). If NativeHistogramBucketFactor is greater than 1 but smaller than + // 2^(2^-8), then the actually used factor is still 2^(2^-8) even though + // it is larger than the provided NativeHistogramBucketFactor. + // + // NOTE: Native Histograms are still an experimental feature. Their + // behavior might still change without a major version + // bump. Subsequently, all NativeHistogram... options here might still + // change their behavior or name (or might completely disappear) without + // a major version bump. + NativeHistogramBucketFactor float64 + // All observations with an absolute value of less or equal + // NativeHistogramZeroThreshold are accumulated into a “zero” + // bucket. For best results, this should be close to a bucket + // boundary. This is usually the case if picking a power of two. If + // NativeHistogramZeroThreshold is left at zero, + // DefSparseBucketsZeroThreshold is used as the threshold. To configure + // a zero bucket with an actual threshold of zero (i.e. only + // observations of precisely zero will go into the zero bucket), set + // NativeHistogramZeroThreshold to the NativeHistogramZeroThresholdZero + // constant (or any negative float value). + NativeHistogramZeroThreshold float64 + + // The remaining fields define a strategy to limit the number of + // populated sparse buckets. If NativeHistogramMaxBucketNumber is left + // at zero, the number of buckets is not limited. (Note that this might + // lead to unbounded memory consumption if the values observed by the + // Histogram are sufficiently wide-spread. In particular, this could be + // used as a DoS attack vector. Where the observed values depend on + // external inputs, it is highly recommended to set a + // NativeHistogramMaxBucketNumber.) Once the set + // NativeHistogramMaxBucketNumber is exceeded, the following strategy is + // enacted: First, if the last reset (or the creation) of the histogram + // is at least NativeHistogramMinResetDuration ago, then the whole + // histogram is reset to its initial state (including regular + // buckets). If less time has passed, or if + // NativeHistogramMinResetDuration is zero, no reset is + // performed. Instead, the zero threshold is increased sufficiently to + // reduce the number of buckets to or below + // NativeHistogramMaxBucketNumber, but not to more than + // NativeHistogramMaxZeroThreshold. Thus, if + // NativeHistogramMaxZeroThreshold is already at or below the current + // zero threshold, nothing happens at this step. After that, if the + // number of buckets still exceeds NativeHistogramMaxBucketNumber, the + // resolution of the histogram is reduced by doubling the width of the + // sparse buckets (up to a growth factor between one bucket to the next + // of 2^(2^4) = 65536, see above). + NativeHistogramMaxBucketNumber uint32 + NativeHistogramMinResetDuration time.Duration + NativeHistogramMaxZeroThreshold float64 } // NewHistogram creates a new Histogram based on the provided HistogramOpts. It @@ -218,16 +503,29 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } } - if len(opts.Buckets) == 0 { - opts.Buckets = DefBuckets - } - h := &histogram{ - desc: desc, - upperBounds: opts.Buckets, - labelPairs: MakeLabelPairs(desc, labelValues), - counts: [2]*histogramCounts{{}, {}}, - now: time.Now, + desc: desc, + upperBounds: opts.Buckets, + labelPairs: MakeLabelPairs(desc, labelValues), + nativeHistogramMaxBuckets: opts.NativeHistogramMaxBucketNumber, + nativeHistogramMaxZeroThreshold: opts.NativeHistogramMaxZeroThreshold, + nativeHistogramMinResetDuration: opts.NativeHistogramMinResetDuration, + lastResetTime: time.Now(), + now: time.Now, + } + if len(h.upperBounds) == 0 && opts.NativeHistogramBucketFactor <= 1 { + h.upperBounds = DefBuckets + } + if opts.NativeHistogramBucketFactor <= 1 { + h.nativeHistogramSchema = math.MinInt32 // To mark that there are no sparse buckets. + } else { + switch { + case opts.NativeHistogramZeroThreshold > 0: + h.nativeHistogramZeroThreshold = opts.NativeHistogramZeroThreshold + case opts.NativeHistogramZeroThreshold == 0: + h.nativeHistogramZeroThreshold = DefNativeHistogramZeroThreshold + } // Leave h.nativeHistogramZeroThreshold at 0 otherwise. + h.nativeHistogramSchema = pickSchema(opts.NativeHistogramBucketFactor) } for i, upperBound := range h.upperBounds { if i < len(h.upperBounds)-1 { @@ -246,8 +544,16 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } // Finally we know the final length of h.upperBounds and can make buckets // for both counts as well as exemplars: - h.counts[0].buckets = make([]uint64, len(h.upperBounds)) - h.counts[1].buckets = make([]uint64, len(h.upperBounds)) + h.counts[0] = &histogramCounts{ + buckets: make([]uint64, len(h.upperBounds)), + nativeHistogramZeroThresholdBits: math.Float64bits(h.nativeHistogramZeroThreshold), + nativeHistogramSchema: h.nativeHistogramSchema, + } + h.counts[1] = &histogramCounts{ + buckets: make([]uint64, len(h.upperBounds)), + nativeHistogramZeroThresholdBits: math.Float64bits(h.nativeHistogramZeroThreshold), + nativeHistogramSchema: h.nativeHistogramSchema, + } h.exemplars = make([]atomic.Value, len(h.upperBounds)+1) h.init(h) // Init self-collection. @@ -255,13 +561,98 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } type histogramCounts struct { + // Order in this struct matters for the alignment required by atomic + // operations, see http://golang.org/pkg/sync/atomic/#pkg-note-BUG + // sumBits contains the bits of the float64 representing the sum of all - // observations. sumBits and count have to go first in the struct to - // guarantee alignment for atomic operations. - // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + // observations. sumBits uint64 count uint64 + + // nativeHistogramZeroBucket counts all (positive and negative) + // observations in the zero bucket (with an absolute value less or equal + // the current threshold, see next field. + nativeHistogramZeroBucket uint64 + // nativeHistogramZeroThresholdBits is the bit pattern of the current + // threshold for the zero bucket. It's initially equal to + // nativeHistogramZeroThreshold but may change according to the bucket + // count limitation strategy. + nativeHistogramZeroThresholdBits uint64 + // nativeHistogramSchema may change over time according to the bucket + // count limitation strategy and therefore has to be saved here. + nativeHistogramSchema int32 + // Number of (positive and negative) sparse buckets. + nativeHistogramBucketsNumber uint32 + + // Regular buckets. buckets []uint64 + + // The sparse buckets for native histograms are implemented with a + // sync.Map for now. A dedicated data structure will likely be more + // efficient. There are separate maps for negative and positive + // observations. The map's value is an *int64, counting observations in + // that bucket. (Note that we don't use uint64 as an int64 won't + // overflow in practice, and working with signed numbers from the + // beginning simplifies the handling of deltas.) The map's key is the + // index of the bucket according to the used + // nativeHistogramSchema. Index 0 is for an upper bound of 1. + nativeHistogramBucketsPositive, nativeHistogramBucketsNegative sync.Map +} + +// observe manages the parts of observe that only affects +// histogramCounts. doSparse is true if sparse buckets should be done, +// too. +func (hc *histogramCounts) observe(v float64, bucket int, doSparse bool) { + if bucket < len(hc.buckets) { + atomic.AddUint64(&hc.buckets[bucket], 1) + } + atomicAddFloat(&hc.sumBits, v) + if doSparse && !math.IsNaN(v) { + var ( + key int + schema = atomic.LoadInt32(&hc.nativeHistogramSchema) + zeroThreshold = math.Float64frombits(atomic.LoadUint64(&hc.nativeHistogramZeroThresholdBits)) + bucketCreated, isInf bool + ) + if math.IsInf(v, 0) { + // Pretend v is MaxFloat64 but later increment key by one. + if math.IsInf(v, +1) { + v = math.MaxFloat64 + } else { + v = -math.MaxFloat64 + } + isInf = true + } + frac, exp := math.Frexp(math.Abs(v)) + if schema > 0 { + bounds := nativeHistogramBounds[schema] + key = sort.SearchFloat64s(bounds, frac) + (exp-1)*len(bounds) + } else { + key = exp + if frac == 0.5 { + key-- + } + div := 1 << -schema + key = (key + div - 1) / div + } + if isInf { + key++ + } + switch { + case v > zeroThreshold: + bucketCreated = addToBucket(&hc.nativeHistogramBucketsPositive, key, 1) + case v < -zeroThreshold: + bucketCreated = addToBucket(&hc.nativeHistogramBucketsNegative, key, 1) + default: + atomic.AddUint64(&hc.nativeHistogramZeroBucket, 1) + } + if bucketCreated { + atomic.AddUint32(&hc.nativeHistogramBucketsNumber, 1) + } + } + // Increment count last as we take it as a signal that the observation + // is complete. + atomic.AddUint64(&hc.count, 1) } type histogram struct { @@ -276,7 +667,7 @@ type histogram struct { // perspective of the histogram) swap the hot–cold under the writeMtx // lock. A cooldown is awaited (while locked) by comparing the number of // observations with the initiation count. Once they match, then the - // last observation on the now cool one has completed. All cool fields must + // last observation on the now cool one has completed. All cold fields must // be merged into the new hot before releasing writeMtx. // // Fields with atomic access first! See alignment constraint: @@ -284,8 +675,10 @@ type histogram struct { countAndHotIdx uint64 selfCollector - desc *Desc - writeMtx sync.Mutex // Only used in the Write method. + desc *Desc + + // Only used in the Write method and for sparse bucket management. + mtx sync.Mutex // Two counts, one is "hot" for lock-free observations, the other is // "cold" for writing out a dto.Metric. It has to be an array of @@ -293,9 +686,15 @@ type histogram struct { // http://golang.org/pkg/sync/atomic/#pkg-note-BUG. counts [2]*histogramCounts - upperBounds []float64 - labelPairs []*dto.LabelPair - exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar. + upperBounds []float64 + labelPairs []*dto.LabelPair + exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar. + nativeHistogramSchema int32 // The initial schema. Set to math.MinInt32 if no sparse buckets are used. + nativeHistogramZeroThreshold float64 // The initial zero threshold. + nativeHistogramMaxZeroThreshold float64 + nativeHistogramMaxBuckets uint32 + nativeHistogramMinResetDuration time.Duration + lastResetTime time.Time // Protected by mtx. now func() time.Time // To mock out time.Now() for testing. } @@ -319,8 +718,8 @@ func (h *histogram) Write(out *dto.Metric) error { // the hot path, i.e. Observe is called much more often than Write. The // complication of making Write lock-free isn't worth it, if possible at // all. - h.writeMtx.Lock() - defer h.writeMtx.Unlock() + h.mtx.Lock() + defer h.mtx.Unlock() // Adding 1<<63 switches the hot index (from 0 to 1 or from 1 to 0) // without touching the count bits. See the struct comments for a full @@ -333,16 +732,16 @@ func (h *histogram) Write(out *dto.Metric) error { hotCounts := h.counts[n>>63] coldCounts := h.counts[(^n)>>63] - // Await cooldown. - for count != atomic.LoadUint64(&coldCounts.count) { - runtime.Gosched() // Let observations get work done. - } + waitForCooldown(count, coldCounts) his := &dto.Histogram{ Bucket: make([]*dto.Bucket, len(h.upperBounds)), SampleCount: proto.Uint64(count), SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), } + out.Histogram = his + out.Label = h.labelPairs + var cumCount uint64 for i, upperBound := range h.upperBounds { cumCount += atomic.LoadUint64(&coldCounts.buckets[i]) @@ -363,25 +762,21 @@ func (h *histogram) Write(out *dto.Metric) error { } his.Bucket = append(his.Bucket, b) } - - out.Histogram = his - out.Label = h.labelPairs - - // Finally add all the cold counts to the new hot counts and reset the cold counts. - atomic.AddUint64(&hotCounts.count, count) - atomic.StoreUint64(&coldCounts.count, 0) - for { - oldBits := atomic.LoadUint64(&hotCounts.sumBits) - newBits := math.Float64bits(math.Float64frombits(oldBits) + his.GetSampleSum()) - if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { - atomic.StoreUint64(&coldCounts.sumBits, 0) - break - } - } - for i := range h.upperBounds { - atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i])) - atomic.StoreUint64(&coldCounts.buckets[i], 0) + if h.nativeHistogramSchema > math.MinInt32 { + his.ZeroThreshold = proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.nativeHistogramZeroThresholdBits))) + his.Schema = proto.Int32(atomic.LoadInt32(&coldCounts.nativeHistogramSchema)) + zeroBucket := atomic.LoadUint64(&coldCounts.nativeHistogramZeroBucket) + + defer func() { + coldCounts.nativeHistogramBucketsPositive.Range(addAndReset(&hotCounts.nativeHistogramBucketsPositive, &hotCounts.nativeHistogramBucketsNumber)) + coldCounts.nativeHistogramBucketsNegative.Range(addAndReset(&hotCounts.nativeHistogramBucketsNegative, &hotCounts.nativeHistogramBucketsNumber)) + }() + + his.ZeroCount = proto.Uint64(zeroBucket) + his.NegativeSpan, his.NegativeDelta = makeBuckets(&coldCounts.nativeHistogramBucketsNegative) + his.PositiveSpan, his.PositiveDelta = makeBuckets(&coldCounts.nativeHistogramBucketsPositive) } + addAndResetCounts(hotCounts, coldCounts) return nil } @@ -402,25 +797,216 @@ func (h *histogram) findBucket(v float64) int { // observe is the implementation for Observe without the findBucket part. func (h *histogram) observe(v float64, bucket int) { + // Do not add to sparse buckets for NaN observations. + doSparse := h.nativeHistogramSchema > math.MinInt32 && !math.IsNaN(v) // We increment h.countAndHotIdx so that the counter in the lower // 63 bits gets incremented. At the same time, we get the new value // back, which we can use to find the currently-hot counts. n := atomic.AddUint64(&h.countAndHotIdx, 1) hotCounts := h.counts[n>>63] + hotCounts.observe(v, bucket, doSparse) + if doSparse { + h.limitBuckets(hotCounts, v, bucket) + } +} - if bucket < len(h.upperBounds) { - atomic.AddUint64(&hotCounts.buckets[bucket], 1) +// limitSparsebuckets applies a strategy to limit the number of populated sparse +// buckets. It's generally best effort, and there are situations where the +// number can go higher (if even the lowest resolution isn't enough to reduce +// the number sufficiently, or if the provided counts aren't fully updated yet +// by a concurrently happening Write call). +func (h *histogram) limitBuckets(counts *histogramCounts, value float64, bucket int) { + if h.nativeHistogramMaxBuckets == 0 { + return // No limit configured. } - for { - oldBits := atomic.LoadUint64(&hotCounts.sumBits) - newBits := math.Float64bits(math.Float64frombits(oldBits) + v) - if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { - break + if h.nativeHistogramMaxBuckets >= atomic.LoadUint32(&counts.nativeHistogramBucketsNumber) { + return // Bucket limit not exceeded yet. + } + + h.mtx.Lock() + defer h.mtx.Unlock() + + // The hot counts might have been swapped just before we acquired the + // lock. Re-fetch the hot counts first... + n := atomic.LoadUint64(&h.countAndHotIdx) + hotIdx := n >> 63 + coldIdx := (^n) >> 63 + hotCounts := h.counts[hotIdx] + coldCounts := h.counts[coldIdx] + // ...and then check again if we really have to reduce the bucket count. + if h.nativeHistogramMaxBuckets >= atomic.LoadUint32(&hotCounts.nativeHistogramBucketsNumber) { + return // Bucket limit not exceeded after all. + } + // Try the various strategies in order. + if h.maybeReset(hotCounts, coldCounts, coldIdx, value, bucket) { + return + } + if h.maybeWidenZeroBucket(hotCounts, coldCounts) { + return + } + h.doubleBucketWidth(hotCounts, coldCounts) +} + +// maybeReset resests the whole histogram if at least h.nativeHistogramMinResetDuration +// has been passed. It returns true if the histogram has been reset. The caller +// must have locked h.mtx. +func (h *histogram) maybeReset(hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int) bool { + // We are using the possibly mocked h.now() rather than + // time.Since(h.lastResetTime) to enable testing. + if h.nativeHistogramMinResetDuration == 0 || h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration { + return false + } + // Completely reset coldCounts. + h.resetCounts(cold) + // Repeat the latest observation to not lose it completely. + cold.observe(value, bucket, true) + // Make coldCounts the new hot counts while ressetting countAndHotIdx. + n := atomic.SwapUint64(&h.countAndHotIdx, (coldIdx<<63)+1) + count := n & ((1 << 63) - 1) + waitForCooldown(count, hot) + // Finally, reset the formerly hot counts, too. + h.resetCounts(hot) + h.lastResetTime = h.now() + return true +} + +// maybeWidenZeroBucket widens the zero bucket until it includes the existing +// buckets closest to the zero bucket (which could be two, if an equidistant +// negative and a positive bucket exists, but usually it's only one bucket to be +// merged into the new wider zero bucket). h.nativeHistogramMaxZeroThreshold +// limits how far the zero bucket can be extended, and if that's not enough to +// include an existing bucket, the method returns false. The caller must have +// locked h.mtx. +func (h *histogram) maybeWidenZeroBucket(hot, cold *histogramCounts) bool { + currentZeroThreshold := math.Float64frombits(atomic.LoadUint64(&hot.nativeHistogramZeroThresholdBits)) + if currentZeroThreshold >= h.nativeHistogramMaxZeroThreshold { + return false + } + // Find the key of the bucket closest to zero. + smallestKey := findSmallestKey(&hot.nativeHistogramBucketsPositive) + smallestNegativeKey := findSmallestKey(&hot.nativeHistogramBucketsNegative) + if smallestNegativeKey < smallestKey { + smallestKey = smallestNegativeKey + } + if smallestKey == math.MaxInt32 { + return false + } + newZeroThreshold := getLe(smallestKey, atomic.LoadInt32(&hot.nativeHistogramSchema)) + if newZeroThreshold > h.nativeHistogramMaxZeroThreshold { + return false // New threshold would exceed the max threshold. + } + atomic.StoreUint64(&cold.nativeHistogramZeroThresholdBits, math.Float64bits(newZeroThreshold)) + // Remove applicable buckets. + if _, loaded := cold.nativeHistogramBucketsNegative.LoadAndDelete(smallestKey); loaded { + atomicDecUint32(&cold.nativeHistogramBucketsNumber) + } + if _, loaded := cold.nativeHistogramBucketsPositive.LoadAndDelete(smallestKey); loaded { + atomicDecUint32(&cold.nativeHistogramBucketsNumber) + } + // Make cold counts the new hot counts. + n := atomic.AddUint64(&h.countAndHotIdx, 1<<63) + count := n & ((1 << 63) - 1) + // Swap the pointer names to represent the new roles and make + // the rest less confusing. + hot, cold = cold, hot + waitForCooldown(count, cold) + // Add all the now cold counts to the new hot counts... + addAndResetCounts(hot, cold) + // ...adjust the new zero threshold in the cold counts, too... + atomic.StoreUint64(&cold.nativeHistogramZeroThresholdBits, math.Float64bits(newZeroThreshold)) + // ...and then merge the newly deleted buckets into the wider zero + // bucket. + mergeAndDeleteOrAddAndReset := func(hotBuckets, coldBuckets *sync.Map) func(k, v interface{}) bool { + return func(k, v interface{}) bool { + key := k.(int) + bucket := v.(*int64) + if key == smallestKey { + // Merge into hot zero bucket... + atomic.AddUint64(&hot.nativeHistogramZeroBucket, uint64(atomic.LoadInt64(bucket))) + // ...and delete from cold counts. + coldBuckets.Delete(key) + atomicDecUint32(&cold.nativeHistogramBucketsNumber) + } else { + // Add to corresponding hot bucket... + if addToBucket(hotBuckets, key, atomic.LoadInt64(bucket)) { + atomic.AddUint32(&hot.nativeHistogramBucketsNumber, 1) + } + // ...and reset cold bucket. + atomic.StoreInt64(bucket, 0) + } + return true } } - // Increment count last as we take it as a signal that the observation - // is complete. - atomic.AddUint64(&hotCounts.count, 1) + + cold.nativeHistogramBucketsPositive.Range(mergeAndDeleteOrAddAndReset(&hot.nativeHistogramBucketsPositive, &cold.nativeHistogramBucketsPositive)) + cold.nativeHistogramBucketsNegative.Range(mergeAndDeleteOrAddAndReset(&hot.nativeHistogramBucketsNegative, &cold.nativeHistogramBucketsNegative)) + return true +} + +// doubleBucketWidth doubles the bucket width (by decrementing the schema +// number). Note that very sparse buckets could lead to a low reduction of the +// bucket count (or even no reduction at all). The method does nothing if the +// schema is already -4. +func (h *histogram) doubleBucketWidth(hot, cold *histogramCounts) { + coldSchema := atomic.LoadInt32(&cold.nativeHistogramSchema) + if coldSchema == -4 { + return // Already at lowest resolution. + } + coldSchema-- + atomic.StoreInt32(&cold.nativeHistogramSchema, coldSchema) + // Play it simple and just delete all cold buckets. + atomic.StoreUint32(&cold.nativeHistogramBucketsNumber, 0) + deleteSyncMap(&cold.nativeHistogramBucketsNegative) + deleteSyncMap(&cold.nativeHistogramBucketsPositive) + // Make coldCounts the new hot counts. + n := atomic.AddUint64(&h.countAndHotIdx, 1<<63) + count := n & ((1 << 63) - 1) + // Swap the pointer names to represent the new roles and make + // the rest less confusing. + hot, cold = cold, hot + waitForCooldown(count, cold) + // Add all the now cold counts to the new hot counts... + addAndResetCounts(hot, cold) + // ...adjust the schema in the cold counts, too... + atomic.StoreInt32(&cold.nativeHistogramSchema, coldSchema) + // ...and then merge the cold buckets into the wider hot buckets. + merge := func(hotBuckets *sync.Map) func(k, v interface{}) bool { + return func(k, v interface{}) bool { + key := k.(int) + bucket := v.(*int64) + // Adjust key to match the bucket to merge into. + if key > 0 { + key++ + } + key /= 2 + // Add to corresponding hot bucket. + if addToBucket(hotBuckets, key, atomic.LoadInt64(bucket)) { + atomic.AddUint32(&hot.nativeHistogramBucketsNumber, 1) + } + return true + } + } + + cold.nativeHistogramBucketsPositive.Range(merge(&hot.nativeHistogramBucketsPositive)) + cold.nativeHistogramBucketsNegative.Range(merge(&hot.nativeHistogramBucketsNegative)) + // Play it simple again and just delete all cold buckets. + atomic.StoreUint32(&cold.nativeHistogramBucketsNumber, 0) + deleteSyncMap(&cold.nativeHistogramBucketsNegative) + deleteSyncMap(&cold.nativeHistogramBucketsPositive) +} + +func (h *histogram) resetCounts(counts *histogramCounts) { + atomic.StoreUint64(&counts.sumBits, 0) + atomic.StoreUint64(&counts.count, 0) + atomic.StoreUint64(&counts.nativeHistogramZeroBucket, 0) + atomic.StoreUint64(&counts.nativeHistogramZeroThresholdBits, math.Float64bits(h.nativeHistogramZeroThreshold)) + atomic.StoreInt32(&counts.nativeHistogramSchema, h.nativeHistogramSchema) + atomic.StoreUint32(&counts.nativeHistogramBucketsNumber, 0) + for i := range h.upperBounds { + atomic.StoreUint64(&counts.buckets[i], 0) + } + deleteSyncMap(&counts.nativeHistogramBucketsNegative) + deleteSyncMap(&counts.nativeHistogramBucketsPositive) } // updateExemplar replaces the exemplar for the provided bucket. With empty @@ -516,7 +1102,8 @@ func (v *HistogramVec) GetMetricWith(labels Labels) (Observer, error) { // WithLabelValues works as GetMetricWithLabelValues, but panics where // GetMetricWithLabelValues would have returned an error. Not returning an // error allows shortcuts like -// myVec.WithLabelValues("404", "GET").Observe(42.21) +// +// myVec.WithLabelValues("404", "GET").Observe(42.21) func (v *HistogramVec) WithLabelValues(lvs ...string) Observer { h, err := v.GetMetricWithLabelValues(lvs...) if err != nil { @@ -527,7 +1114,8 @@ func (v *HistogramVec) WithLabelValues(lvs ...string) Observer { // 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"}).Observe(42.21) +// +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21) func (v *HistogramVec) With(labels Labels) Observer { h, err := v.GetMetricWith(labels) if err != nil { @@ -581,11 +1169,11 @@ func (h *constHistogram) Desc() *Desc { func (h *constHistogram) Write(out *dto.Metric) error { his := &dto.Histogram{} + buckets := make([]*dto.Bucket, 0, len(h.buckets)) his.SampleCount = proto.Uint64(h.count) his.SampleSum = proto.Float64(h.sum) - for upperBound, count := range h.buckets { buckets = append(buckets, &dto.Bucket{ CumulativeCount: proto.Uint64(count), @@ -613,7 +1201,7 @@ func (h *constHistogram) Write(out *dto.Metric) error { // to send it to Prometheus in the Collect method. // // buckets is a map of upper bounds to cumulative counts, excluding the +Inf -// bucket. +// bucket. The +Inf bucket is implicit, and its value is equal to the provided count. // // NewConstHistogram returns an error if the length of labelValues is not // consistent with the variable labels in Desc or if Desc is invalid. @@ -668,3 +1256,229 @@ func (s buckSort) Swap(i, j int) { func (s buckSort) Less(i, j int) bool { return s[i].GetUpperBound() < s[j].GetUpperBound() } + +// pickSchema returns the largest number n between -4 and 8 such that +// 2^(2^-n) is less or equal the provided bucketFactor. +// +// Special cases: +// - bucketFactor <= 1: panics. +// - bucketFactor < 2^(2^-8) (but > 1): still returns 8. +func pickSchema(bucketFactor float64) int32 { + if bucketFactor <= 1 { + panic(fmt.Errorf("bucketFactor %f is <=1", bucketFactor)) + } + floor := math.Floor(math.Log2(math.Log2(bucketFactor))) + switch { + case floor <= -8: + return 8 + case floor >= 4: + return -4 + default: + return -int32(floor) + } +} + +func makeBuckets(buckets *sync.Map) ([]*dto.BucketSpan, []int64) { + var ii []int + buckets.Range(func(k, v interface{}) bool { + ii = append(ii, k.(int)) + return true + }) + sort.Ints(ii) + + if len(ii) == 0 { + return nil, nil + } + + var ( + spans []*dto.BucketSpan + deltas []int64 + prevCount int64 + nextI int + ) + + appendDelta := func(count int64) { + *spans[len(spans)-1].Length++ + deltas = append(deltas, count-prevCount) + prevCount = count + } + + for n, i := range ii { + v, _ := buckets.Load(i) + count := atomic.LoadInt64(v.(*int64)) + // Multiple spans with only small gaps in between are probably + // encoded more efficiently as one larger span with a few empty + // buckets. Needs some research to find the sweet spot. For now, + // we assume that gaps of one ore two buckets should not create + // a new span. + iDelta := int32(i - nextI) + if n == 0 || iDelta > 2 { + // We have to create a new span, either because we are + // at the very beginning, or because we have found a gap + // of more than two buckets. + spans = append(spans, &dto.BucketSpan{ + Offset: proto.Int32(iDelta), + Length: proto.Uint32(0), + }) + } else { + // We have found a small gap (or no gap at all). + // Insert empty buckets as needed. + for j := int32(0); j < iDelta; j++ { + appendDelta(0) + } + } + appendDelta(count) + nextI = i + 1 + } + return spans, deltas +} + +// addToBucket increments the sparse bucket at key by the provided amount. It +// returns true if a new sparse bucket had to be created for that. +func addToBucket(buckets *sync.Map, key int, increment int64) bool { + if existingBucket, ok := buckets.Load(key); ok { + // Fast path without allocation. + atomic.AddInt64(existingBucket.(*int64), increment) + return false + } + // Bucket doesn't exist yet. Slow path allocating new counter. + newBucket := increment // TODO(beorn7): Check if this is sufficient to not let increment escape. + if actualBucket, loaded := buckets.LoadOrStore(key, &newBucket); loaded { + // The bucket was created concurrently in another goroutine. + // Have to increment after all. + atomic.AddInt64(actualBucket.(*int64), increment) + return false + } + return true +} + +// addAndReset returns a function to be used with sync.Map.Range of spare +// buckets in coldCounts. It increments the buckets in the provided hotBuckets +// according to the buckets ranged through. It then resets all buckets ranged +// through to 0 (but leaves them in place so that they don't need to get +// recreated on the next scrape). +func addAndReset(hotBuckets *sync.Map, bucketNumber *uint32) func(k, v interface{}) bool { + return func(k, v interface{}) bool { + bucket := v.(*int64) + if addToBucket(hotBuckets, k.(int), atomic.LoadInt64(bucket)) { + atomic.AddUint32(bucketNumber, 1) + } + atomic.StoreInt64(bucket, 0) + return true + } +} + +func deleteSyncMap(m *sync.Map) { + m.Range(func(k, v interface{}) bool { + m.Delete(k) + return true + }) +} + +func findSmallestKey(m *sync.Map) int { + result := math.MaxInt32 + m.Range(func(k, v interface{}) bool { + key := k.(int) + if key < result { + result = key + } + return true + }) + return result +} + +func getLe(key int, schema int32) float64 { + // Here a bit of context about the behavior for the last bucket counting + // regular numbers (called simply "last bucket" below) and the bucket + // counting observations of ±Inf (called "inf bucket" below, with a key + // one higher than that of the "last bucket"): + // + // If we apply the usual formula to the last bucket, its upper bound + // would be calculated as +Inf. The reason is that the max possible + // regular float64 number (math.MaxFloat64) doesn't coincide with one of + // the calculated bucket boundaries. So the calculated boundary has to + // be larger than math.MaxFloat64, and the only float64 larger than + // math.MaxFloat64 is +Inf. However, we want to count actual + // observations of ±Inf in the inf bucket. Therefore, we have to treat + // the upper bound of the last bucket specially and set it to + // math.MaxFloat64. (The upper bound of the inf bucket, with its key + // being one higher than that of the last bucket, naturally comes out as + // +Inf by the usual formula. So that's fine.) + // + // math.MaxFloat64 has a frac of 0.9999999999999999 and an exp of + // 1024. If there were a float64 number following math.MaxFloat64, it + // would have a frac of 1.0 and an exp of 1024, or equivalently a frac + // of 0.5 and an exp of 1025. However, since frac must be smaller than + // 1, and exp must be smaller than 1025, either representation overflows + // a float64. (Which, in turn, is the reason that math.MaxFloat64 is the + // largest possible float64. Q.E.D.) However, the formula for + // calculating the upper bound from the idx and schema of the last + // bucket results in precisely that. It is either frac=1.0 & exp=1024 + // (for schema < 0) or frac=0.5 & exp=1025 (for schema >=0). (This is, + // by the way, a power of two where the exponent itself is a power of + // two, 2¹⁰ in fact, which coinicides with a bucket boundary in all + // schemas.) So these are the special cases we have to catch below. + if schema < 0 { + exp := key << -schema + if exp == 1024 { + // This is the last bucket before the overflow bucket + // (for ±Inf observations). Return math.MaxFloat64 as + // explained above. + return math.MaxFloat64 + } + return math.Ldexp(1, exp) + } + + fracIdx := key & ((1 << schema) - 1) + frac := nativeHistogramBounds[schema][fracIdx] + exp := (key >> schema) + 1 + if frac == 0.5 && exp == 1025 { + // This is the last bucket before the overflow bucket (for ±Inf + // observations). Return math.MaxFloat64 as explained above. + return math.MaxFloat64 + } + return math.Ldexp(frac, exp) +} + +// waitForCooldown returns after the count field in the provided histogramCounts +// has reached the provided count value. +func waitForCooldown(count uint64, counts *histogramCounts) { + for count != atomic.LoadUint64(&counts.count) { + runtime.Gosched() // Let observations get work done. + } +} + +// atomicAddFloat adds the provided float atomically to another float +// represented by the bit pattern the bits pointer is pointing to. +func atomicAddFloat(bits *uint64, v float64) { + for { + loadedBits := atomic.LoadUint64(bits) + newBits := math.Float64bits(math.Float64frombits(loadedBits) + v) + if atomic.CompareAndSwapUint64(bits, loadedBits, newBits) { + break + } + } +} + +// atomicDecUint32 atomically decrements the uint32 p points to. See +// https://pkg.go.dev/sync/atomic#AddUint32 to understand how this is done. +func atomicDecUint32(p *uint32) { + atomic.AddUint32(p, ^uint32(0)) +} + +// addAndResetCounts adds certain fields (count, sum, conventional buckets, zero +// bucket) from the cold counts to the corresponding fields in the hot +// counts. Those fields are then reset to 0 in the cold counts. +func addAndResetCounts(hot, cold *histogramCounts) { + atomic.AddUint64(&hot.count, atomic.LoadUint64(&cold.count)) + atomic.StoreUint64(&cold.count, 0) + coldSum := math.Float64frombits(atomic.LoadUint64(&cold.sumBits)) + atomicAddFloat(&hot.sumBits, coldSum) + atomic.StoreUint64(&cold.sumBits, 0) + for i := range hot.buckets { + atomic.AddUint64(&hot.buckets[i], atomic.LoadUint64(&cold.buckets[i])) + atomic.StoreUint64(&cold.buckets[i], 0) + } + atomic.AddUint64(&hot.nativeHistogramZeroBucket, atomic.LoadUint64(&cold.nativeHistogramZeroBucket)) + atomic.StoreUint64(&cold.nativeHistogramZeroBucket, 0) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go new file mode 100644 index 000000000..1ed5abe74 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/almost_equal.go @@ -0,0 +1,60 @@ +// Copyright (c) 2015 Björn Rabenstein +// +// 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. +// +// The code in this package is copy/paste to avoid a dependency. Hence this file +// carries the copyright of the original repo. +// https://github.com/beorn7/floats +package internal + +import ( + "math" +) + +// minNormalFloat64 is the smallest positive normal value of type float64. +var minNormalFloat64 = math.Float64frombits(0x0010000000000000) + +// AlmostEqualFloat64 returns true if a and b are equal within a relative error +// of epsilon. See http://floating-point-gui.de/errors/comparison/ for the +// details of the applied method. +func AlmostEqualFloat64(a, b, epsilon float64) bool { + if a == b { + return true + } + absA := math.Abs(a) + absB := math.Abs(b) + diff := math.Abs(a - b) + if a == 0 || b == 0 || absA+absB < minNormalFloat64 { + return diff < epsilon*minNormalFloat64 + } + return diff/math.Min(absA+absB, math.MaxFloat64) < epsilon +} + +// AlmostEqualFloat64s is the slice form of AlmostEqualFloat64. +func AlmostEqualFloat64s(a, b []float64, epsilon float64) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if !AlmostEqualFloat64(a[i], b[i], epsilon) { + return false + } + } + return true +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go new file mode 100644 index 000000000..fd0750f2c --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go @@ -0,0 +1,654 @@ +// Copyright 2022 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. +// +// It provides tools to compare sequences of strings and generate textual diffs. +// +// Maintaining `GetUnifiedDiffString` here because original repository +// (https://github.com/pmezard/go-difflib) is no loger maintained. +package internal + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strings" +) + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func calculateRatio(matches, length int) float64 { + if length > 0 { + return 2.0 * float64(matches) / float64(length) + } + return 1.0 +} + +type Match struct { + A int + B int + Size int +} + +type OpCode struct { + Tag byte + I1 int + I2 int + J1 int + J2 int +} + +// SequenceMatcher compares sequence of strings. The basic +// algorithm predates, and is a little fancier than, an algorithm +// published in the late 1980's by Ratcliff and Obershelp under the +// hyperbolic name "gestalt pattern matching". The basic idea is to find +// the longest contiguous matching subsequence that contains no "junk" +// elements (R-O doesn't address junk). The same idea is then applied +// recursively to the pieces of the sequences to the left and to the right +// of the matching subsequence. This does not yield minimal edit +// sequences, but does tend to yield matches that "look right" to people. +// +// SequenceMatcher tries to compute a "human-friendly diff" between two +// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the +// longest *contiguous* & junk-free matching subsequence. That's what +// catches peoples' eyes. The Windows(tm) windiff has another interesting +// notion, pairing up elements that appear uniquely in each sequence. +// That, and the method here, appear to yield more intuitive difference +// reports than does diff. This method appears to be the least vulnerable +// to synching up on blocks of "junk lines", though (like blank lines in +// ordinary text files, or maybe "

" lines in HTML files). That may be +// because this is the only method of the 3 that has a *concept* of +// "junk" . +// +// Timing: Basic R-O is cubic time worst case and quadratic time expected +// case. SequenceMatcher is quadratic time for the worst case and has +// expected-case behavior dependent in a complicated way on how many +// elements the sequences have in common; best case time is linear. +type SequenceMatcher struct { + a []string + b []string + b2j map[string][]int + IsJunk func(string) bool + autoJunk bool + bJunk map[string]struct{} + matchingBlocks []Match + fullBCount map[string]int + bPopular map[string]struct{} + opCodes []OpCode +} + +func NewMatcher(a, b []string) *SequenceMatcher { + m := SequenceMatcher{autoJunk: true} + m.SetSeqs(a, b) + return &m +} + +func NewMatcherWithJunk(a, b []string, autoJunk bool, + isJunk func(string) bool, +) *SequenceMatcher { + m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk} + m.SetSeqs(a, b) + return &m +} + +// Set two sequences to be compared. +func (m *SequenceMatcher) SetSeqs(a, b []string) { + m.SetSeq1(a) + m.SetSeq2(b) +} + +// Set the first sequence to be compared. The second sequence to be compared is +// not changed. +// +// SequenceMatcher computes and caches detailed information about the second +// sequence, so if you want to compare one sequence S against many sequences, +// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other +// sequences. +// +// See also SetSeqs() and SetSeq2(). +func (m *SequenceMatcher) SetSeq1(a []string) { + if &a == &m.a { + return + } + m.a = a + m.matchingBlocks = nil + m.opCodes = nil +} + +// Set the second sequence to be compared. The first sequence to be compared is +// not changed. +func (m *SequenceMatcher) SetSeq2(b []string) { + if &b == &m.b { + return + } + m.b = b + m.matchingBlocks = nil + m.opCodes = nil + m.fullBCount = nil + m.chainB() +} + +func (m *SequenceMatcher) chainB() { + // Populate line -> index mapping + b2j := map[string][]int{} + for i, s := range m.b { + indices := b2j[s] + indices = append(indices, i) + b2j[s] = indices + } + + // Purge junk elements + m.bJunk = map[string]struct{}{} + if m.IsJunk != nil { + junk := m.bJunk + for s := range b2j { + if m.IsJunk(s) { + junk[s] = struct{}{} + } + } + for s := range junk { + delete(b2j, s) + } + } + + // Purge remaining popular elements + popular := map[string]struct{}{} + n := len(m.b) + if m.autoJunk && n >= 200 { + ntest := n/100 + 1 + for s, indices := range b2j { + if len(indices) > ntest { + popular[s] = struct{}{} + } + } + for s := range popular { + delete(b2j, s) + } + } + m.bPopular = popular + m.b2j = b2j +} + +func (m *SequenceMatcher) isBJunk(s string) bool { + _, ok := m.bJunk[s] + return ok +} + +// Find longest matching block in a[alo:ahi] and b[blo:bhi]. +// +// If IsJunk is not defined: +// +// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where +// +// alo <= i <= i+k <= ahi +// blo <= j <= j+k <= bhi +// +// and for all (i',j',k') meeting those conditions, +// +// k >= k' +// i <= i' +// and if i == i', j <= j' +// +// In other words, of all maximal matching blocks, return one that +// starts earliest in a, and of all those maximal matching blocks that +// start earliest in a, return the one that starts earliest in b. +// +// If IsJunk is defined, first the longest matching block is +// determined as above, but with the additional restriction that no +// junk element appears in the block. Then that block is extended as +// far as possible by matching (only) junk elements on both sides. So +// the resulting block never matches on junk except as identical junk +// happens to be adjacent to an "interesting" match. +// +// If no blocks match, return (alo, blo, 0). +func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match { + // CAUTION: stripping common prefix or suffix would be incorrect. + // E.g., + // ab + // acab + // Longest matching block is "ab", but if common prefix is + // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so + // strip, so ends up claiming that ab is changed to acab by + // inserting "ca" in the middle. That's minimal but unintuitive: + // "it's obvious" that someone inserted "ac" at the front. + // Windiff ends up at the same place as diff, but by pairing up + // the unique 'b's and then matching the first two 'a's. + besti, bestj, bestsize := alo, blo, 0 + + // find longest junk-free match + // during an iteration of the loop, j2len[j] = length of longest + // junk-free match ending with a[i-1] and b[j] + j2len := map[int]int{} + for i := alo; i != ahi; i++ { + // look at all instances of a[i] in b; note that because + // b2j has no junk keys, the loop is skipped if a[i] is junk + newj2len := map[int]int{} + for _, j := range m.b2j[m.a[i]] { + // a[i] matches b[j] + if j < blo { + continue + } + if j >= bhi { + break + } + k := j2len[j-1] + 1 + newj2len[j] = k + if k > bestsize { + besti, bestj, bestsize = i-k+1, j-k+1, k + } + } + j2len = newj2len + } + + // Extend the best by non-junk elements on each end. In particular, + // "popular" non-junk elements aren't in b2j, which greatly speeds + // the inner loop above, but also means "the best" match so far + // doesn't contain any junk *or* popular non-junk elements. + for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + !m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize++ + } + + // Now that we have a wholly interesting match (albeit possibly + // empty!), we may as well suck up the matching junk on each + // side of it too. Can't think of a good reason not to, and it + // saves post-processing the (possibly considerable) expense of + // figuring out what to do with it. In the case of an empty + // interesting match, this is clearly the right thing to do, + // because no other kind of match is possible in the regions. + for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize++ + } + + return Match{A: besti, B: bestj, Size: bestsize} +} + +// Return list of triples describing matching subsequences. +// +// Each triple is of the form (i, j, n), and means that +// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in +// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are +// adjacent triples in the list, and the second is not the last triple in the +// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe +// adjacent equal blocks. +// +// The last triple is a dummy, (len(a), len(b), 0), and is the only +// triple with n==0. +func (m *SequenceMatcher) GetMatchingBlocks() []Match { + if m.matchingBlocks != nil { + return m.matchingBlocks + } + + var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match + matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match { + match := m.findLongestMatch(alo, ahi, blo, bhi) + i, j, k := match.A, match.B, match.Size + if match.Size > 0 { + if alo < i && blo < j { + matched = matchBlocks(alo, i, blo, j, matched) + } + matched = append(matched, match) + if i+k < ahi && j+k < bhi { + matched = matchBlocks(i+k, ahi, j+k, bhi, matched) + } + } + return matched + } + matched := matchBlocks(0, len(m.a), 0, len(m.b), nil) + + // It's possible that we have adjacent equal blocks in the + // matching_blocks list now. + nonAdjacent := []Match{} + i1, j1, k1 := 0, 0, 0 + for _, b := range matched { + // Is this block adjacent to i1, j1, k1? + i2, j2, k2 := b.A, b.B, b.Size + if i1+k1 == i2 && j1+k1 == j2 { + // Yes, so collapse them -- this just increases the length of + // the first block by the length of the second, and the first + // block so lengthened remains the block to compare against. + k1 += k2 + } else { + // Not adjacent. Remember the first block (k1==0 means it's + // the dummy we started with), and make the second block the + // new block to compare against. + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + i1, j1, k1 = i2, j2, k2 + } + } + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + + nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0}) + m.matchingBlocks = nonAdjacent + return m.matchingBlocks +} + +// Return list of 5-tuples describing how to turn a into b. +// +// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple +// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the +// tuple preceding it, and likewise for j1 == the previous j2. +// +// The tags are characters, with these meanings: +// +// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2] +// +// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case. +// +// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case. +// +// 'e' (equal): a[i1:i2] == b[j1:j2] +func (m *SequenceMatcher) GetOpCodes() []OpCode { + if m.opCodes != nil { + return m.opCodes + } + i, j := 0, 0 + matching := m.GetMatchingBlocks() + opCodes := make([]OpCode, 0, len(matching)) + for _, m := range matching { + // invariant: we've pumped out correct diffs to change + // a[:i] into b[:j], and the next matching block is + // a[ai:ai+size] == b[bj:bj+size]. So we need to pump + // out a diff to change a[i:ai] into b[j:bj], pump out + // the matching block, and move (i,j) beyond the match + ai, bj, size := m.A, m.B, m.Size + tag := byte(0) + if i < ai && j < bj { + tag = 'r' + } else if i < ai { + tag = 'd' + } else if j < bj { + tag = 'i' + } + if tag > 0 { + opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) + } + i, j = ai+size, bj+size + // the list of matching blocks is terminated by a + // sentinel with size 0 + if size > 0 { + opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) + } + } + m.opCodes = opCodes + return m.opCodes +} + +// Isolate change clusters by eliminating ranges with no changes. +// +// Return a generator of groups with up to n lines of context. +// Each group is in the same format as returned by GetOpCodes(). +func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { + if n < 0 { + n = 3 + } + codes := m.GetOpCodes() + if len(codes) == 0 { + codes = []OpCode{{'e', 0, 1, 0, 1}} + } + // Fixup leading and trailing groups if they show no changes. + if codes[0].Tag == 'e' { + c := codes[0] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2} + } + if codes[len(codes)-1].Tag == 'e' { + c := codes[len(codes)-1] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)} + } + nn := n + n + groups := [][]OpCode{} + group := []OpCode{} + for _, c := range codes { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + // End the current group and start a new one whenever + // there is a large range with no changes. + if c.Tag == 'e' && i2-i1 > nn { + group = append(group, OpCode{ + c.Tag, i1, min(i2, i1+n), + j1, min(j2, j1+n), + }) + groups = append(groups, group) + group = []OpCode{} + i1, j1 = max(i1, i2-n), max(j1, j2-n) + } + group = append(group, OpCode{c.Tag, i1, i2, j1, j2}) + } + if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') { + groups = append(groups, group) + } + return groups +} + +// Return a measure of the sequences' similarity (float in [0,1]). +// +// Where T is the total number of elements in both sequences, and +// M is the number of matches, this is 2.0*M / T. +// Note that this is 1 if the sequences are identical, and 0 if +// they have nothing in common. +// +// .Ratio() is expensive to compute if you haven't already computed +// .GetMatchingBlocks() or .GetOpCodes(), in which case you may +// want to try .QuickRatio() or .RealQuickRation() first to get an +// upper bound. +func (m *SequenceMatcher) Ratio() float64 { + matches := 0 + for _, m := range m.GetMatchingBlocks() { + matches += m.Size + } + return calculateRatio(matches, len(m.a)+len(m.b)) +} + +// Return an upper bound on ratio() relatively quickly. +// +// This isn't defined beyond that it is an upper bound on .Ratio(), and +// is faster to compute. +func (m *SequenceMatcher) QuickRatio() float64 { + // viewing a and b as multisets, set matches to the cardinality + // of their intersection; this counts the number of matches + // without regard to order, so is clearly an upper bound + if m.fullBCount == nil { + m.fullBCount = map[string]int{} + for _, s := range m.b { + m.fullBCount[s]++ + } + } + + // avail[x] is the number of times x appears in 'b' less the + // number of times we've seen it in 'a' so far ... kinda + avail := map[string]int{} + matches := 0 + for _, s := range m.a { + n, ok := avail[s] + if !ok { + n = m.fullBCount[s] + } + avail[s] = n - 1 + if n > 0 { + matches++ + } + } + return calculateRatio(matches, len(m.a)+len(m.b)) +} + +// Return an upper bound on ratio() very quickly. +// +// This isn't defined beyond that it is an upper bound on .Ratio(), and +// is faster to compute than either .Ratio() or .QuickRatio(). +func (m *SequenceMatcher) RealQuickRatio() float64 { + la, lb := len(m.a), len(m.b) + return calculateRatio(min(la, lb), la+lb) +} + +// Convert range to the "ed" format +func formatRangeUnified(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 1 { + return fmt.Sprintf("%d", beginning) + } + if length == 0 { + beginning-- // empty ranges begin at line just before the range + } + return fmt.Sprintf("%d,%d", beginning, length) +} + +// Unified diff parameters +type UnifiedDiff struct { + A []string // First sequence lines + FromFile string // First file name + FromDate string // First file time + B []string // Second sequence lines + ToFile string // Second file name + ToDate string // Second file time + Eol string // Headers end of line, defaults to LF + Context int // Number of context lines +} + +// Compare two sequences of lines; generate the delta as a unified diff. +// +// Unified diffs are a compact way of showing line changes and a few +// lines of context. The number of context lines is set by 'n' which +// defaults to three. +// +// By default, the diff control lines (those with ---, +++, or @@) are +// created with a trailing newline. This is helpful so that inputs +// created from file.readlines() result in diffs that are suitable for +// file.writelines() since both the inputs and outputs have trailing +// newlines. +// +// For inputs that do not have trailing newlines, set the lineterm +// argument to "" so that the output will be uniformly newline free. +// +// The unidiff format normally has a header for filenames and modification +// times. Any or all of these may be specified using strings for +// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. +// The modification times are normally expressed in the ISO 8601 format. +func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { + buf := bufio.NewWriter(writer) + defer buf.Flush() + wf := func(format string, args ...interface{}) error { + _, err := buf.WriteString(fmt.Sprintf(format, args...)) + return err + } + ws := func(s string) error { + _, err := buf.WriteString(s) + return err + } + + if len(diff.Eol) == 0 { + diff.Eol = "\n" + } + + started := false + m := NewMatcher(diff.A, diff.B) + for _, g := range m.GetGroupedOpCodes(diff.Context) { + if !started { + started = true + fromDate := "" + if len(diff.FromDate) > 0 { + fromDate = "\t" + diff.FromDate + } + toDate := "" + if len(diff.ToDate) > 0 { + toDate = "\t" + diff.ToDate + } + if diff.FromFile != "" || diff.ToFile != "" { + err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) + if err != nil { + return err + } + err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) + if err != nil { + return err + } + } + } + first, last := g[0], g[len(g)-1] + range1 := formatRangeUnified(first.I1, last.I2) + range2 := formatRangeUnified(first.J1, last.J2) + if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil { + return err + } + for _, c := range g { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + if c.Tag == 'e' { + for _, line := range diff.A[i1:i2] { + if err := ws(" " + line); err != nil { + return err + } + } + continue + } + if c.Tag == 'r' || c.Tag == 'd' { + for _, line := range diff.A[i1:i2] { + if err := ws("-" + line); err != nil { + return err + } + } + } + if c.Tag == 'r' || c.Tag == 'i' { + for _, line := range diff.B[j1:j2] { + if err := ws("+" + line); err != nil { + return err + } + } + } + } + } + return nil +} + +// Like WriteUnifiedDiff but returns the diff a string. +func GetUnifiedDiffString(diff UnifiedDiff) (string, error) { + w := &bytes.Buffer{} + err := WriteUnifiedDiff(w, diff) + return w.String(), err +} + +// Split a string on "\n" while preserving them. The output can be used +// as input for UnifiedDiff and ContextDiff structures. +func SplitLines(s string) []string { + lines := strings.SplitAfter(s, "\n") + lines[len(lines)-1] += "\n" + return lines +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go new file mode 100644 index 000000000..723b45d64 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/go_collector_options.go @@ -0,0 +1,32 @@ +// 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 internal + +import "regexp" + +type GoCollectorRule struct { + Matcher *regexp.Regexp + Deny bool +} + +// GoCollectorOptions should not be used be directly by anything, except `collectors` package. +// Use it via collectors package instead. See issue +// https://github.com/prometheus/client_golang/issues/1030. +// +// This is internal, so external users only can use it via `collector.WithGoCollector*` methods +type GoCollectorOptions struct { + DisableMemStatsLikeMetrics bool + RuntimeMetricSumForHist map[string]string + RuntimeMetricRules []GoCollectorRule +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go index fe0a52180..97d17d6cb 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/go_runtime_metrics.go @@ -61,9 +61,9 @@ func RuntimeMetricsToProm(d *metrics.Description) (string, string, string, bool) // name has - replaced with _ and is concatenated with the unit and // other data. name = strings.ReplaceAll(name, "-", "_") - name = name + "_" + unit - if d.Cumulative { - name = name + "_total" + name += "_" + unit + if d.Cumulative && d.Kind != metrics.KindFloat64Histogram { + name += "_total" } valid := model.IsValidMetricName(model.LabelValue(namespace + "_" + subsystem + "_" + name)) @@ -84,12 +84,12 @@ func RuntimeMetricsToProm(d *metrics.Description) (string, string, string, bool) func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 { switch unit { case "bytes": - // Rebucket as powers of 2. - return rebucketExp(buckets, 2) + // Re-bucket as powers of 2. + return reBucketExp(buckets, 2) case "seconds": - // Rebucket as powers of 10 and then merge all buckets greater + // Re-bucket as powers of 10 and then merge all buckets greater // than 1 second into the +Inf bucket. - b := rebucketExp(buckets, 10) + b := reBucketExp(buckets, 10) for i := range b { if b[i] <= 1 { continue @@ -103,11 +103,11 @@ func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 { return buckets } -// rebucketExp takes a list of bucket boundaries (lower bound inclusive) and +// reBucketExp takes a list of bucket boundaries (lower bound inclusive) and // downsamples the buckets to those a multiple of base apart. The end result // is a roughly exponential (in many cases, perfectly exponential) bucketing // scheme. -func rebucketExp(buckets []float64, base float64) []float64 { +func reBucketExp(buckets []float64, base float64) []float64 { bucket := buckets[0] var newBuckets []float64 // We may see a -Inf here, in which case, add it and skip it diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go index 351c26e1a..6515c1148 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go @@ -19,18 +19,34 @@ import ( dto "github.com/prometheus/client_model/go" ) -// metricSorter is a sortable slice of *dto.Metric. -type metricSorter []*dto.Metric +// LabelPairSorter implements sort.Interface. It is used to sort a slice of +// dto.LabelPair pointers. +type LabelPairSorter []*dto.LabelPair -func (s metricSorter) Len() int { +func (s LabelPairSorter) Len() int { return len(s) } -func (s metricSorter) Swap(i, j int) { +func (s LabelPairSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s metricSorter) Less(i, j int) bool { +func (s LabelPairSorter) Less(i, j int) bool { + return s[i].GetName() < s[j].GetName() +} + +// MetricSorter is a sortable slice of *dto.Metric. +type MetricSorter []*dto.Metric + +func (s MetricSorter) Len() int { + return len(s) +} + +func (s MetricSorter) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s MetricSorter) Less(i, j int) bool { if len(s[i].Label) != len(s[j].Label) { // This should not happen. The metrics are // inconsistent. However, we have to deal with the fact, as @@ -68,7 +84,7 @@ func (s metricSorter) Less(i, j int) bool { // the slice, with the contained Metrics sorted within each MetricFamily. func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { for _, mf := range metricFamiliesByName { - sort.Sort(metricSorter(mf.Metric)) + sort.Sort(MetricSorter(mf.Metric)) } names := make([]string, 0, len(metricFamiliesByName)) for name, mf := range metricFamiliesByName { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go index 2744443ac..c1b8fad36 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/labels.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go @@ -25,7 +25,8 @@ import ( // Labels represents a collection of label name -> value mappings. This type is // commonly used with the With(Labels) and GetMetricWith(Labels) methods of // metric vector Collectors, e.g.: -// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) +// +// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42) // // The other use-case is the specification of constant label pairs in Opts or to // create a Desc. @@ -39,7 +40,7 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality") func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { return fmt.Errorf( - "%s: %q has %d variable labels named %q but %d values %q were provided", + "%w: %q has %d variable labels named %q but %d values %q were provided", errInconsistentCardinality, fqName, len(labels), labels, len(labelValues), labelValues, @@ -49,7 +50,7 @@ func makeInconsistentCardinalityError(fqName string, labels, labelValues []strin func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { if len(labels) != expectedNumberOfValues { return fmt.Errorf( - "%s: expected %d label values but got %d in %#v", + "%w: expected %d label values but got %d in %#v", errInconsistentCardinality, expectedNumberOfValues, len(labels), labels, ) @@ -67,7 +68,7 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { func validateLabelValues(vals []string, expectedNumberOfValues int) error { if len(vals) != expectedNumberOfValues { return fmt.Errorf( - "%s: expected %d label values but got %d in %#v", + "%w: expected %d label values but got %d in %#v", errInconsistentCardinality, expectedNumberOfValues, len(vals), vals, ) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go index dc121910a..b5119c504 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go @@ -14,6 +14,9 @@ package prometheus import ( + "errors" + "math" + "sort" "strings" "time" @@ -115,22 +118,6 @@ func BuildFQName(namespace, subsystem, name string) string { return name } -// labelPairSorter implements sort.Interface. It is used to sort a slice of -// dto.LabelPair pointers. -type labelPairSorter []*dto.LabelPair - -func (s labelPairSorter) Len() int { - return len(s) -} - -func (s labelPairSorter) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s labelPairSorter) Less(i, j int) bool { - return s[i].GetName() < s[j].GetName() -} - type invalidMetric struct { desc *Desc err error @@ -174,3 +161,96 @@ func (m timestampedMetric) Write(pb *dto.Metric) error { func NewMetricWithTimestamp(t time.Time, m Metric) Metric { return timestampedMetric{Metric: m, t: t} } + +type withExemplarsMetric struct { + Metric + + exemplars []*dto.Exemplar +} + +func (m *withExemplarsMetric) Write(pb *dto.Metric) error { + if err := m.Metric.Write(pb); err != nil { + return err + } + + switch { + case pb.Counter != nil: + pb.Counter.Exemplar = m.exemplars[len(m.exemplars)-1] + case pb.Histogram != nil: + for _, e := range m.exemplars { + // pb.Histogram.Bucket are sorted by UpperBound. + i := sort.Search(len(pb.Histogram.Bucket), func(i int) bool { + return pb.Histogram.Bucket[i].GetUpperBound() >= e.GetValue() + }) + if i < len(pb.Histogram.Bucket) { + pb.Histogram.Bucket[i].Exemplar = e + } else { + // The +Inf bucket should be explicitly added if there is an exemplar for it, similar to non-const histogram logic in https://github.com/prometheus/client_golang/blob/main/prometheus/histogram.go#L357-L365. + b := &dto.Bucket{ + CumulativeCount: proto.Uint64(pb.Histogram.GetSampleCount()), + UpperBound: proto.Float64(math.Inf(1)), + Exemplar: e, + } + pb.Histogram.Bucket = append(pb.Histogram.Bucket, b) + } + } + default: + // TODO(bwplotka): Implement Gauge? + return errors.New("cannot inject exemplar into Gauge, Summary or Untyped") + } + + return nil +} + +// Exemplar is easier to use, user-facing representation of *dto.Exemplar. +type Exemplar struct { + Value float64 + Labels Labels + // Optional. + // Default value (time.Time{}) indicates its empty, which should be + // understood as time.Now() time at the moment of creation of metric. + Timestamp time.Time +} + +// NewMetricWithExemplars returns a new Metric wrapping the provided Metric with given +// exemplars. Exemplars are validated. +// +// Only last applicable exemplar is injected from the list. +// For example for Counter it means last exemplar is injected. +// For Histogram, it means last applicable exemplar for each bucket is injected. +// +// NewMetricWithExemplars works best with MustNewConstMetric and +// MustNewConstHistogram, see example. +func NewMetricWithExemplars(m Metric, exemplars ...Exemplar) (Metric, error) { + if len(exemplars) == 0 { + return nil, errors.New("no exemplar was passed for NewMetricWithExemplars") + } + + var ( + now = time.Now() + exs = make([]*dto.Exemplar, len(exemplars)) + err error + ) + for i, e := range exemplars { + ts := e.Timestamp + if ts == (time.Time{}) { + ts = now + } + exs[i], err = newExemplar(e.Value, ts, e.Labels) + if err != nil { + return nil, err + } + } + + return &withExemplarsMetric{Metric: m, exemplars: exs}, nil +} + +// MustNewMetricWithExemplars is a version of NewMetricWithExemplars that panics where +// NewMetricWithExemplars would have returned an error. +func MustNewMetricWithExemplars(m Metric, exemplars ...Exemplar) Metric { + ret, err := NewMetricWithExemplars(m, exemplars...) + if err != nil { + panic(err) + } + return ret +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go b/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go new file mode 100644 index 000000000..7c12b2108 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/num_threads.go @@ -0,0 +1,25 @@ +// Copyright 2018 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. + +//go:build !js || wasm +// +build !js wasm + +package prometheus + +import "runtime" + +// getRuntimeNumThreads returns the number of open OS threads. +func getRuntimeNumThreads() float64 { + n, _ := runtime.ThreadCreateProfile(nil) + return float64(n) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go b/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go new file mode 100644 index 000000000..7348df01d --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/num_threads_gopherjs.go @@ -0,0 +1,22 @@ +// Copyright 2018 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. + +//go:build js && !wasm +// +build js,!wasm + +package prometheus + +// getRuntimeNumThreads returns the number of open OS threads. +func getRuntimeNumThreads() float64 { + return 1 +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/observer.go b/vendor/github.com/prometheus/client_golang/prometheus/observer.go index 44128016f..03773b21f 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/observer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/observer.go @@ -58,7 +58,7 @@ type ObserverVec interface { // 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. ObserveWithExemplar panics if any of the provided labels are -// invalid or if the provided labels contain more than 64 runes in total. +// invalid or if the provided labels contain more than 128 runes in total. type ExemplarObserver interface { ObserveWithExemplar(value float64, exemplar Labels) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go index 5bfe0ff5b..8548dd18e 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector.go @@ -16,7 +16,6 @@ package prometheus import ( "errors" "fmt" - "io/ioutil" "os" "strconv" "strings" @@ -104,8 +103,7 @@ func NewProcessCollector(opts ProcessCollectorOpts) Collector { } if opts.PidFn == nil { - pid := os.Getpid() - c.pidFn = func() (int, error) { return pid, nil } + c.pidFn = getPIDFn() } else { c.pidFn = opts.PidFn } @@ -152,13 +150,13 @@ func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) // It is meant to be used for the PidFn field in ProcessCollectorOpts. func NewPidFileFn(pidFilePath string) func() (int, error) { return func() (int, error) { - content, err := ioutil.ReadFile(pidFilePath) + content, err := os.ReadFile(pidFilePath) if err != nil { - return 0, fmt.Errorf("can't read pid file %q: %+v", pidFilePath, err) + return 0, fmt.Errorf("can't read pid file %q: %w", pidFilePath, err) } pid, err := strconv.Atoi(strings.TrimSpace(string(content))) if err != nil { - return 0, fmt.Errorf("can't parse pid file %q: %+v", pidFilePath, err) + return 0, fmt.Errorf("can't parse pid file %q: %w", pidFilePath, err) } return pid, nil diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_js.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_js.go new file mode 100644 index 000000000..b1e363d6c --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_js.go @@ -0,0 +1,26 @@ +// Copyright 2019 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. + +//go:build js +// +build js + +package prometheus + +func canCollectProcess() bool { + return false +} + +func (c *processCollector) processCollect(ch chan<- Metric) { + // noop on this platform + return +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go index 2dc3660da..c0152cdb6 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go @@ -11,8 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !windows -// +build !windows +//go:build !windows && !js +// +build !windows,!js package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go index e7c0d0546..9819917b8 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go @@ -76,16 +76,19 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) { return n, err } -type closeNotifierDelegator struct{ *responseWriterDelegator } -type flusherDelegator struct{ *responseWriterDelegator } -type hijackerDelegator struct{ *responseWriterDelegator } -type readerFromDelegator struct{ *responseWriterDelegator } -type pusherDelegator struct{ *responseWriterDelegator } +type ( + closeNotifierDelegator struct{ *responseWriterDelegator } + flusherDelegator struct{ *responseWriterDelegator } + hijackerDelegator struct{ *responseWriterDelegator } + readerFromDelegator struct{ *responseWriterDelegator } + pusherDelegator struct{ *responseWriterDelegator } +) func (d closeNotifierDelegator) CloseNotify() <-chan bool { //nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users. return d.ResponseWriter.(http.CloseNotifier).CloseNotify() } + func (d flusherDelegator) Flush() { // If applicable, call WriteHeader here so that observeWriteHeader is // handled appropriately. @@ -94,9 +97,11 @@ func (d flusherDelegator) Flush() { } d.ResponseWriter.(http.Flusher).Flush() } + func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { return d.ResponseWriter.(http.Hijacker).Hijack() } + func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { // If applicable, call WriteHeader here so that observeWriteHeader is // handled appropriately. @@ -107,6 +112,7 @@ func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { d.written += n return n, err } + func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { return d.ResponseWriter.(http.Pusher).Push(target, opts) } @@ -261,7 +267,7 @@ func init() { http.Flusher }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} } - pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 + pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 23 return struct { *responseWriterDelegator http.Pusher diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go index d86d0cf4b..a4cc9810b 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -33,6 +33,7 @@ package promhttp import ( "compress/gzip" + "errors" "fmt" "io" "net/http" @@ -84,6 +85,13 @@ func Handler() http.Handler { // instrumentation. Use the InstrumentMetricHandler function to apply the same // kind of instrumentation as it is used by the Handler function. func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { + return HandlerForTransactional(prometheus.ToTransactionalGatherer(reg), opts) +} + +// HandlerForTransactional is like HandlerFor, but it uses transactional gather, which +// can safely change in-place returned *dto.MetricFamily before call to `Gather` and after +// call to `done` of that `Gather`. +func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerOpts) http.Handler { var ( inFlightSem chan struct{} errCnt = prometheus.NewCounterVec( @@ -103,7 +111,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { errCnt.WithLabelValues("gathering") errCnt.WithLabelValues("encoding") if err := opts.Registry.Register(errCnt); err != nil { - if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + are := &prometheus.AlreadyRegisteredError{} + if errors.As(err, are) { errCnt = are.ExistingCollector.(*prometheus.CounterVec) } else { panic(err) @@ -123,7 +132,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { return } } - mfs, err := reg.Gather() + mfs, done, err := reg.Gather() + defer done() if err != nil { if opts.ErrorLog != nil { opts.ErrorLog.Println("error gathering metrics:", err) @@ -242,7 +252,8 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht cnt.WithLabelValues("500") cnt.WithLabelValues("503") if err := reg.Register(cnt); err != nil { - if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + are := &prometheus.AlreadyRegisteredError{} + if errors.As(err, are) { cnt = are.ExistingCollector.(*prometheus.CounterVec) } else { panic(err) @@ -254,7 +265,8 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht Help: "Current number of scrapes being served.", }) if err := reg.Register(gge); err != nil { - if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + are := &prometheus.AlreadyRegisteredError{} + if errors.As(err, are) { gge = are.ExistingCollector.(prometheus.Gauge) } else { panic(err) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go index 861b4d21c..210867816 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go @@ -38,11 +38,11 @@ func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { // // See the example for ExampleInstrumentRoundTripperDuration for example usage. func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc { - return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + return func(r *http.Request) (*http.Response, error) { gauge.Inc() defer gauge.Dec() return next.RoundTrip(r) - }) + } } // InstrumentRoundTripperCounter is a middleware that wraps the provided @@ -59,22 +59,28 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp // If the wrapped RoundTripper panics or returns a non-nil error, the Counter // is not incremented. // +// Use with WithExemplarFromContext to instrument the exemplars on the counter of requests. +// // See the example for ExampleInstrumentRoundTripperDuration for example usage. func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc { - rtOpts := &option{} + rtOpts := defaultOptions() for _, o := range opts { - o(rtOpts) + o.apply(rtOpts) } code, method := checkLabels(counter) - return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + return func(r *http.Request) (*http.Response, error) { resp, err := next.RoundTrip(r) if err == nil { - counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc() + addWithExemplar( + counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)), + 1, + rtOpts.getExemplarFn(r.Context()), + ) } return resp, err - }) + } } // InstrumentRoundTripperDuration is a middleware that wraps the provided @@ -94,24 +100,30 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou // If the wrapped RoundTripper panics or returns a non-nil error, no values are // reported. // +// Use with WithExemplarFromContext to instrument the exemplars on the duration histograms. +// // Note that this method is only guaranteed to never observe negative durations // if used with Go1.9+. func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc { - rtOpts := &option{} + rtOpts := defaultOptions() for _, o := range opts { - o(rtOpts) + o.apply(rtOpts) } code, method := checkLabels(obs) - return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + return func(r *http.Request) (*http.Response, error) { start := time.Now() resp, err := next.RoundTrip(r) if err == nil { - obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds()) + observeWithExemplar( + obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)), + time.Since(start).Seconds(), + rtOpts.getExemplarFn(r.Context()), + ) } return resp, err - }) + } } // InstrumentTrace is used to offer flexibility in instrumenting the available @@ -149,7 +161,7 @@ type InstrumentTrace struct { // // See the example for ExampleInstrumentRoundTripperDuration for example usage. func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { - return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { + return func(r *http.Request) (*http.Response, error) { start := time.Now() trace := &httptrace.ClientTrace{ @@ -231,5 +243,5 @@ func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) Ro r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace)) return next.RoundTrip(r) - }) + } } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go index a23f0edc6..cca67a78a 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go @@ -28,6 +28,26 @@ import ( // magicString is used for the hacky label test in checkLabels. Remove once fixed. const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa" +// observeWithExemplar is a wrapper for [prometheus.ExemplarAdder.ExemplarObserver], +// which falls back to [prometheus.Observer.Observe] if no labels are provided. +func observeWithExemplar(obs prometheus.Observer, val float64, labels map[string]string) { + if labels == nil { + obs.Observe(val) + return + } + obs.(prometheus.ExemplarObserver).ObserveWithExemplar(val, labels) +} + +// addWithExemplar is a wrapper for [prometheus.ExemplarAdder.AddWithExemplar], +// which falls back to [prometheus.Counter.Add] if no labels are provided. +func addWithExemplar(obs prometheus.Counter, val float64, labels map[string]string) { + if labels == nil { + obs.Add(val) + return + } + obs.(prometheus.ExemplarAdder).AddWithExemplar(val, labels) +} + // InstrumentHandlerInFlight is a middleware that wraps the provided // http.Handler. It sets the provided prometheus.Gauge to the number of // requests currently handled by the wrapped http.Handler. @@ -48,7 +68,7 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl // names are "code" and "method". The function panics otherwise. For the "method" // label a predefined default label value set is used to filter given values. // Values besides predefined values will count as `unknown` method. -//`WithExtraMethods` can be used to add more methods to the set. The Observe +// `WithExtraMethods` can be used to add more methods to the set. The Observe // method of the Observer in the ObserverVec is called with the request duration // in seconds. Partitioning happens by HTTP status code and/or HTTP method if // the respective instance label names are present in the ObserverVec. For @@ -62,28 +82,37 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl // Note that this method is only guaranteed to never observe negative durations // if used with Go1.9+. func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc { - mwOpts := &option{} + hOpts := defaultOptions() for _, o := range opts { - o(mwOpts) + o.apply(hOpts) } code, method := checkLabels(obs) if code { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { now := time.Now() d := newDelegator(w, nil) next.ServeHTTP(d, r) - obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds()) - }) + observeWithExemplar( + obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), + time.Since(now).Seconds(), + hOpts.getExemplarFn(r.Context()), + ) + } } - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { now := time.Now() next.ServeHTTP(w, r) - obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds()) - }) + + observeWithExemplar( + obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)), + time.Since(now).Seconds(), + hOpts.getExemplarFn(r.Context()), + ) + } } // InstrumentHandlerCounter is a middleware that wraps the provided http.Handler @@ -104,25 +133,34 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op // // See the example for InstrumentHandlerDuration for example usage. func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc { - mwOpts := &option{} + hOpts := defaultOptions() for _, o := range opts { - o(mwOpts) + o.apply(hOpts) } code, method := checkLabels(counter) if code { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { d := newDelegator(w, nil) next.ServeHTTP(d, r) - counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc() - }) + + addWithExemplar( + counter.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), + 1, + hOpts.getExemplarFn(r.Context()), + ) + } } - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) - counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc() - }) + addWithExemplar( + counter.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)), + 1, + hOpts.getExemplarFn(r.Context()), + ) + } } // InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided @@ -148,20 +186,24 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, // // See the example for InstrumentHandlerDuration for example usage. func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc { - mwOpts := &option{} + hOpts := defaultOptions() for _, o := range opts { - o(mwOpts) + o.apply(hOpts) } code, method := checkLabels(obs) - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { now := time.Now() d := newDelegator(w, func(status int) { - obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds()) + observeWithExemplar( + obs.With(labels(code, method, r.Method, status, hOpts.extraMethods...)), + time.Since(now).Seconds(), + hOpts.getExemplarFn(r.Context()), + ) }) next.ServeHTTP(d, r) - }) + } } // InstrumentHandlerRequestSize is a middleware that wraps the provided @@ -184,27 +226,34 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha // // See the example for InstrumentHandlerDuration for example usage. func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc { - mwOpts := &option{} + hOpts := defaultOptions() for _, o := range opts { - o(mwOpts) + o.apply(hOpts) } code, method := checkLabels(obs) - if code { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { d := newDelegator(w, nil) next.ServeHTTP(d, r) size := computeApproximateRequestSize(r) - obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size)) - }) + observeWithExemplar( + obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), + float64(size), + hOpts.getExemplarFn(r.Context()), + ) + } } - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) size := computeApproximateRequestSize(r) - obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size)) - }) + observeWithExemplar( + obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)), + float64(size), + hOpts.getExemplarFn(r.Context()), + ) + } } // InstrumentHandlerResponseSize is a middleware that wraps the provided @@ -227,9 +276,9 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, // // See the example for InstrumentHandlerDuration for example usage. func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler { - mwOpts := &option{} + hOpts := defaultOptions() for _, o := range opts { - o(mwOpts) + o.apply(hOpts) } code, method := checkLabels(obs) @@ -237,7 +286,11 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { d := newDelegator(w, nil) next.ServeHTTP(d, r) - obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written())) + observeWithExemplar( + obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), + float64(d.Written()), + hOpts.getExemplarFn(r.Context()), + ) }) } @@ -246,7 +299,7 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler // Collector does not have a Desc or has more than one Desc or its Desc is // invalid. It also panics if the Collector has any non-const, non-curried // labels that are not named "code" or "method". -func checkLabels(c prometheus.Collector) (code bool, method bool) { +func checkLabels(c prometheus.Collector) (code, method bool) { // TODO(beorn7): Remove this hacky way to check for instance labels // once Descriptors can have their dimensionality queried. var ( diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go index 35e41bd1e..c590d912c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go @@ -13,19 +13,46 @@ package promhttp -// Option are used to configure a middleware or round tripper.. -type Option func(*option) +import ( + "context" -type option struct { - extraMethods []string + "github.com/prometheus/client_golang/prometheus" +) + +// Option are used to configure both handler (middleware) or round tripper. +type Option interface { + apply(*options) +} + +// options store options for both a handler or round tripper. +type options struct { + extraMethods []string + getExemplarFn func(requestCtx context.Context) prometheus.Labels +} + +func defaultOptions() *options { + return &options{getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil }} } +type optionApplyFunc func(*options) + +func (o optionApplyFunc) apply(opt *options) { o(opt) } + // WithExtraMethods adds additional HTTP methods to the list of allowed methods. // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list. // // See the example for ExampleInstrumentHandlerWithExtraMethods for example usage. func WithExtraMethods(methods ...string) Option { - return func(o *option) { + return optionApplyFunc(func(o *options) { o.extraMethods = methods - } + }) +} + +// WithExemplarFromContext adds allows to put a hook to all counter and histogram metrics. +// If the hook function returns non-nil labels, exemplars will be added for that request, otherwise metric +// will get instrumented without exemplar. +func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option { + return optionApplyFunc(func(o *options) { + o.getExemplarFn = getExemplarFn + }) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index 383a7f594..09e34d307 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -15,8 +15,8 @@ package prometheus import ( "bytes" + "errors" "fmt" - "io/ioutil" "os" "path/filepath" "runtime" @@ -252,9 +252,12 @@ func (errs MultiError) MaybeUnwrap() error { } // Registry registers Prometheus collectors, collects their metrics, and gathers -// them into MetricFamilies for exposition. It implements both Registerer and -// Gatherer. The zero value is not usable. Create instances with NewRegistry or -// NewPedanticRegistry. +// them into MetricFamilies for exposition. It implements Registerer, Gatherer, +// and Collector. The zero value is not usable. Create instances with +// NewRegistry or NewPedanticRegistry. +// +// Registry implements Collector to allow it to be used for creating groups of +// metrics. See the Grouping example for how this can be done. type Registry struct { mtx sync.RWMutex collectorsByID map[uint64]Collector // ID is a hash of the descIDs. @@ -289,7 +292,7 @@ func (r *Registry) Register(c Collector) error { // Is the descriptor valid at all? if desc.err != nil { - return fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err) + return fmt.Errorf("descriptor %s is invalid: %w", desc, desc.err) } // Is the descID unique? @@ -407,6 +410,14 @@ func (r *Registry) MustRegister(cs ...Collector) { // Gather implements Gatherer. func (r *Registry) Gather() ([]*dto.MetricFamily, error) { + r.mtx.RLock() + + if len(r.collectorsByID) == 0 && len(r.uncheckedCollectors) == 0 { + // Fast path. + r.mtx.RUnlock() + return nil, nil + } + var ( checkedMetricChan = make(chan Metric, capMetricChan) uncheckedMetricChan = make(chan Metric, capMetricChan) @@ -416,7 +427,6 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { registeredDescIDs map[uint64]struct{} // Only used for pedantic checks ) - r.mtx.RLock() goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors) metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) checkedCollectors := make(chan Collector, len(r.collectorsByID)) @@ -549,6 +559,31 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() } +// Describe implements Collector. +func (r *Registry) Describe(ch chan<- *Desc) { + r.mtx.RLock() + defer r.mtx.RUnlock() + + // Only report the checked Collectors; unchecked collectors don't report any + // Desc. + for _, c := range r.collectorsByID { + c.Describe(ch) + } +} + +// Collect implements Collector. +func (r *Registry) Collect(ch chan<- Metric) { + r.mtx.RLock() + defer r.mtx.RUnlock() + + for _, c := range r.collectorsByID { + c.Collect(ch) + } + for _, c := range r.uncheckedCollectors { + c.Collect(ch) + } +} + // WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the // Prometheus text format, and writes it to a temporary file. Upon success, the // temporary file is renamed to the provided filename. @@ -556,7 +591,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { // This is intended for use with the textfile collector of the node exporter. // Note that the node exporter expects the filename to be suffixed with ".prom". func WriteToTextfile(filename string, g Gatherer) error { - tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) + tmp, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename)) if err != nil { return err } @@ -575,7 +610,7 @@ func WriteToTextfile(filename string, g Gatherer) error { return err } - if err := os.Chmod(tmp.Name(), 0644); err != nil { + if err := os.Chmod(tmp.Name(), 0o644); err != nil { return err } return os.Rename(tmp.Name(), filename) @@ -596,7 +631,7 @@ func processMetric( } dtoMetric := &dto.Metric{} if err := metric.Write(dtoMetric); err != nil { - return fmt.Errorf("error collecting metric %v: %s", desc, err) + return fmt.Errorf("error collecting metric %v: %w", desc, err) } metricFamily, ok := metricFamiliesByName[desc.fqName] if ok { // Existing name. @@ -718,12 +753,13 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { for i, g := range gs { mfs, err := g.Gather() if err != nil { - if multiErr, ok := err.(MultiError); ok { + multiErr := MultiError{} + if errors.As(err, &multiErr) { for _, err := range multiErr { - errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) + errs = append(errs, fmt.Errorf("[from Gatherer #%d] %w", i+1, err)) } } else { - errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) + errs = append(errs, fmt.Errorf("[from Gatherer #%d] %w", i+1, err)) } } for _, mf := range mfs { @@ -884,11 +920,11 @@ func checkMetricConsistency( h.Write(separatorByteSlice) // Make sure label pairs are sorted. We depend on it for the consistency // check. - if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { + if !sort.IsSorted(internal.LabelPairSorter(dtoMetric.Label)) { // We cannot sort dtoMetric.Label in place as it is immutable by contract. copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) copy(copiedLabels, dtoMetric.Label) - sort.Sort(labelPairSorter(copiedLabels)) + sort.Sort(internal.LabelPairSorter(copiedLabels)) dtoMetric.Label = copiedLabels } for _, lp := range dtoMetric.Label { @@ -935,7 +971,7 @@ func checkDescConsistency( metricFamily.GetName(), dtoMetric, desc, ) } - sort.Sort(labelPairSorter(lpsFromDesc)) + sort.Sort(internal.LabelPairSorter(lpsFromDesc)) for i, lpFromDesc := range lpsFromDesc { lpFromMetric := dtoMetric.Label[i] if lpFromDesc.GetName() != lpFromMetric.GetName() || @@ -948,3 +984,89 @@ func checkDescConsistency( } return nil } + +var _ TransactionalGatherer = &MultiTRegistry{} + +// MultiTRegistry is a TransactionalGatherer that joins gathered metrics from multiple +// transactional gatherers. +// +// It is caller responsibility to ensure two registries have mutually exclusive metric families, +// no deduplication will happen. +type MultiTRegistry struct { + tGatherers []TransactionalGatherer +} + +// NewMultiTRegistry creates MultiTRegistry. +func NewMultiTRegistry(tGatherers ...TransactionalGatherer) *MultiTRegistry { + return &MultiTRegistry{ + tGatherers: tGatherers, + } +} + +// Gather implements TransactionalGatherer interface. +func (r *MultiTRegistry) Gather() (mfs []*dto.MetricFamily, done func(), err error) { + errs := MultiError{} + + dFns := make([]func(), 0, len(r.tGatherers)) + // TODO(bwplotka): Implement concurrency for those? + for _, g := range r.tGatherers { + // TODO(bwplotka): Check for duplicates? + m, d, err := g.Gather() + errs.Append(err) + + mfs = append(mfs, m...) + dFns = append(dFns, d) + } + + // TODO(bwplotka): Consider sort in place, given metric family in gather is sorted already. + sort.Slice(mfs, func(i, j int) bool { + return *mfs[i].Name < *mfs[j].Name + }) + return mfs, func() { + for _, d := range dFns { + d() + } + }, errs.MaybeUnwrap() +} + +// TransactionalGatherer represents transactional gatherer that can be triggered to notify gatherer that memory +// used by metric family is no longer used by a caller. This allows implementations with cache. +type TransactionalGatherer interface { + // Gather returns metrics in a lexicographically sorted slice + // of uniquely named MetricFamily protobufs. Gather ensures that the + // returned slice is valid and self-consistent so that it can be used + // for valid exposition. As an exception to the strict consistency + // requirements described for metric.Desc, Gather will tolerate + // different sets of label names for metrics of the same metric family. + // + // Even if an error occurs, Gather attempts to gather as many metrics as + // possible. Hence, if a non-nil error is returned, the returned + // MetricFamily slice could be nil (in case of a fatal error that + // prevented any meaningful metric collection) or contain a number of + // MetricFamily protobufs, some of which might be incomplete, and some + // might be missing altogether. The returned error (which might be a + // MultiError) explains the details. Note that this is mostly useful for + // debugging purposes. If the gathered protobufs are to be used for + // exposition in actual monitoring, it is almost always better to not + // expose an incomplete result and instead disregard the returned + // MetricFamily protobufs in case the returned error is non-nil. + // + // Important: done is expected to be triggered (even if the error occurs!) + // once caller does not need returned slice of dto.MetricFamily. + Gather() (_ []*dto.MetricFamily, done func(), err error) +} + +// ToTransactionalGatherer transforms Gatherer to transactional one with noop as done function. +func ToTransactionalGatherer(g Gatherer) TransactionalGatherer { + return &noTransactionGatherer{g: g} +} + +type noTransactionGatherer struct { + g Gatherer +} + +// Gather implements TransactionalGatherer interface. +func (g *noTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(), err error) { + mfs, err := g.g.Gather() + return mfs, func() {}, err +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index c5fa8ed7c..7bc448a89 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -603,7 +603,8 @@ func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) { // WithLabelValues works as GetMetricWithLabelValues, but panics where // GetMetricWithLabelValues would have returned an error. Not returning an // error allows shortcuts like -// myVec.WithLabelValues("404", "GET").Observe(42.21) +// +// myVec.WithLabelValues("404", "GET").Observe(42.21) func (v *SummaryVec) WithLabelValues(lvs ...string) Observer { s, err := v.GetMetricWithLabelValues(lvs...) if err != nil { @@ -614,7 +615,8 @@ func (v *SummaryVec) WithLabelValues(lvs ...string) Observer { // 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"}).Observe(42.21) +// +// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21) func (v *SummaryVec) With(labels Labels) Observer { s, err := v.GetMetricWith(labels) if err != nil { @@ -701,7 +703,8 @@ func (s *constSummary) Write(out *dto.Metric) error { // // quantiles maps ranks to quantile values. For example, a median latency of // 0.23s and a 99th percentile latency of 0.56s would be expressed as: -// map[float64]float64{0.5: 0.23, 0.99: 0.56} +// +// map[float64]float64{0.5: 0.23, 0.99: 0.56} // // NewConstSummary returns an error if the length of labelValues is not // consistent with the variable labels in Desc or if Desc is invalid. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go index ec8061706..a20f159b7 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go @@ -15,6 +15,7 @@ package promlint import ( + "errors" "fmt" "io" "regexp" @@ -83,7 +84,7 @@ func (l *Linter) Lint() ([]Problem, error) { mf := &dto.MetricFamily{} for { if err := d.Decode(mf); err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } @@ -283,7 +284,7 @@ func lintUnitAbbreviations(mf *dto.MetricFamily) []Problem { // metricUnits attempts to detect known unit types used as part of a metric name, // e.g. "foo_bytes_total" or "bar_baz_milligrams". -func metricUnits(m string) (unit string, base string, ok bool) { +func metricUnits(m string) (unit, base string, ok bool) { ss := strings.Split(m, "_") for unit, base := range units { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go index 8d5f10523..f28a76f3a 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/timer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go @@ -25,11 +25,12 @@ type Timer struct { // NewTimer creates a new Timer. The provided Observer is used to observe a // duration in seconds. Timer is usually used to time a function call in the // following way: -// func TimeMe() { -// timer := NewTimer(myHistogram) -// defer timer.ObserveDuration() -// // Do actual work. -// } +// +// func TimeMe() { +// timer := NewTimer(myHistogram) +// defer timer.ObserveDuration() +// // Do actual work. +// } func NewTimer(o Observer) *Timer { return &Timer{ begin: time.Now(), diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go index b4e0ae11c..2d3abc1cb 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go @@ -23,6 +23,8 @@ import ( "github.com/golang/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/prometheus/client_golang/prometheus/internal" + dto "github.com/prometheus/client_model/go" ) @@ -38,6 +40,23 @@ const ( UntypedValue ) +var ( + CounterMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_COUNTER; return &d }() + GaugeMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_GAUGE; return &d }() + UntypedMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_UNTYPED; return &d }() +) + +func (v ValueType) ToDTO() *dto.MetricType { + switch v { + case CounterValue: + return CounterMetricTypePtr + case GaugeValue: + return GaugeMetricTypePtr + default: + return UntypedMetricTypePtr + } +} + // valueFunc is a generic metric for simple values retrieved on collect time // from a function. It implements Metric and Collector. Its effective type is // determined by ValueType. This is a low-level building block used by the @@ -91,11 +110,15 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { return nil, err } + + metric := &dto.Metric{} + if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil { + return nil, err + } + return &constMetric{ - desc: desc, - valType: valueType, - val: value, - labelPairs: MakeLabelPairs(desc, labelValues), + desc: desc, + metric: metric, }, nil } @@ -110,10 +133,8 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal } type constMetric struct { - desc *Desc - valType ValueType - val float64 - labelPairs []*dto.LabelPair + desc *Desc + metric *dto.Metric } func (m *constMetric) Desc() *Desc { @@ -121,7 +142,11 @@ func (m *constMetric) Desc() *Desc { } func (m *constMetric) Write(out *dto.Metric) error { - return populateMetric(m.valType, m.val, m.labelPairs, nil, out) + out.Label = m.metric.Label + out.Counter = m.metric.Counter + out.Gauge = m.metric.Gauge + out.Untyped = m.metric.Untyped + return nil } func populateMetric( @@ -170,12 +195,12 @@ func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { }) } labelPairs = append(labelPairs, desc.constLabelPairs...) - sort.Sort(labelPairSorter(labelPairs)) + sort.Sort(internal.LabelPairSorter(labelPairs)) return labelPairs } // ExemplarMaxRunes is the max total number of runes allowed in exemplar labels. -const ExemplarMaxRunes = 64 +const ExemplarMaxRunes = 128 // newExemplar creates a new dto.Exemplar from the provided values. An error is // returned if any of the label names or values are invalid or if the total diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec.go b/vendor/github.com/prometheus/client_golang/prometheus/vec.go index 4ababe6c9..7ae322590 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/vec.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/vec.go @@ -99,6 +99,16 @@ func (m *MetricVec) Delete(labels Labels) bool { return m.metricMap.deleteByHashWithLabels(h, labels, m.curry) } +// DeletePartialMatch deletes all metrics where the variable labels contain all of those +// passed in as labels. The order of the labels does not matter. +// It returns the number of metrics deleted. +// +// Note that curried labels will never be matched if deleting from the curried vector. +// To match curried labels with DeletePartialMatch, it must be called on the base vector. +func (m *MetricVec) DeletePartialMatch(labels Labels) int { + return m.metricMap.deleteByLabels(labels, m.curry) +} + // Without explicit forwarding of Describe, Collect, Reset, those methods won't // show up in GoDoc. @@ -381,6 +391,82 @@ func (m *metricMap) deleteByHashWithLabels( return true } +// deleteByLabels deletes a metric if the given labels are present in the metric. +func (m *metricMap) deleteByLabels(labels Labels, curry []curriedLabelValue) int { + m.mtx.Lock() + defer m.mtx.Unlock() + + var numDeleted int + + for h, metrics := range m.metrics { + i := findMetricWithPartialLabels(m.desc, metrics, labels, curry) + if i >= len(metrics) { + // Didn't find matching labels in this metric slice. + continue + } + delete(m.metrics, h) + numDeleted++ + } + + return numDeleted +} + +// findMetricWithPartialLabel returns the index of the matching metric or +// len(metrics) if not found. +func findMetricWithPartialLabels( + desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue, +) int { + for i, metric := range metrics { + if matchPartialLabels(desc, metric.values, labels, curry) { + return i + } + } + return len(metrics) +} + +// indexOf searches the given slice of strings for the target string and returns +// the index or len(items) as well as a boolean whether the search succeeded. +func indexOf(target string, items []string) (int, bool) { + for i, l := range items { + if l == target { + return i, true + } + } + return len(items), false +} + +// valueMatchesVariableOrCurriedValue determines if a value was previously curried, +// and returns whether it matches either the "base" value or the curried value accordingly. +// It also indicates whether the match is against a curried or uncurried value. +func valueMatchesVariableOrCurriedValue(targetValue string, index int, values []string, curry []curriedLabelValue) (bool, bool) { + for _, curriedValue := range curry { + if curriedValue.index == index { + // This label was curried. See if the curried value matches our target. + return curriedValue.value == targetValue, true + } + } + // This label was not curried. See if the current value matches our target label. + return values[index] == targetValue, false +} + +// matchPartialLabels searches the current metric and returns whether all of the target label:value pairs are present. +func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool { + for l, v := range labels { + // Check if the target label exists in our metrics and get the index. + varLabelIndex, validLabel := indexOf(l, desc.variableLabels) + if validLabel { + // Check the value of that label against the target value. + // We don't consider curried values in partial matches. + matches, curried := valueMatchesVariableOrCurriedValue(v, varLabelIndex, values, curry) + if matches && !curried { + continue + } + } + return false + } + return true +} + // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value // or creates it and returns the new one. // @@ -485,7 +571,7 @@ func findMetricWithLabels( return len(metrics) } -func matchLabelValues(values []string, lvs []string, curry []curriedLabelValue) bool { +func matchLabelValues(values, lvs []string, curry []curriedLabelValue) bool { if len(values) != len(lvs)+len(curry) { return false } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go index 74ee93280..1498ee144 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go @@ -21,6 +21,8 @@ import ( "github.com/golang/protobuf/proto" dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/client_golang/prometheus/internal" ) // WrapRegistererWith returns a Registerer wrapping the provided @@ -182,7 +184,7 @@ func (m *wrappingMetric) Write(out *dto.Metric) error { Value: proto.String(lv), }) } - sort.Sort(labelPairSorter(out.Label)) + sort.Sort(internal.LabelPairSorter(out.Label)) return nil } diff --git a/vendor/github.com/prometheus/client_model/go/metrics.pb.go b/vendor/github.com/prometheus/client_model/go/metrics.pb.go index 2f4930d9d..35904ea19 100644 --- a/vendor/github.com/prometheus/client_model/go/metrics.pb.go +++ b/vendor/github.com/prometheus/client_model/go/metrics.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go. DO NOT EDIT. -// source: metrics.proto +// source: io/prometheus/client/metrics.proto package io_prometheus_client @@ -24,11 +24,18 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type MetricType int32 const ( - MetricType_COUNTER MetricType = 0 - MetricType_GAUGE MetricType = 1 - MetricType_SUMMARY MetricType = 2 - MetricType_UNTYPED MetricType = 3 + // COUNTER must use the Metric field "counter". + MetricType_COUNTER MetricType = 0 + // GAUGE must use the Metric field "gauge". + MetricType_GAUGE MetricType = 1 + // SUMMARY must use the Metric field "summary". + MetricType_SUMMARY MetricType = 2 + // UNTYPED must use the Metric field "untyped". + MetricType_UNTYPED MetricType = 3 + // HISTOGRAM must use the Metric field "histogram". MetricType_HISTOGRAM MetricType = 4 + // GAUGE_HISTOGRAM must use the Metric field "histogram". + MetricType_GAUGE_HISTOGRAM MetricType = 5 ) var MetricType_name = map[int32]string{ @@ -37,14 +44,16 @@ var MetricType_name = map[int32]string{ 2: "SUMMARY", 3: "UNTYPED", 4: "HISTOGRAM", + 5: "GAUGE_HISTOGRAM", } var MetricType_value = map[string]int32{ - "COUNTER": 0, - "GAUGE": 1, - "SUMMARY": 2, - "UNTYPED": 3, - "HISTOGRAM": 4, + "COUNTER": 0, + "GAUGE": 1, + "SUMMARY": 2, + "UNTYPED": 3, + "HISTOGRAM": 4, + "GAUGE_HISTOGRAM": 5, } func (x MetricType) Enum() *MetricType { @@ -67,7 +76,7 @@ func (x *MetricType) UnmarshalJSON(data []byte) error { } func (MetricType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{0} + return fileDescriptor_d1e5ddb18987a258, []int{0} } type LabelPair struct { @@ -82,7 +91,7 @@ func (m *LabelPair) Reset() { *m = LabelPair{} } func (m *LabelPair) String() string { return proto.CompactTextString(m) } func (*LabelPair) ProtoMessage() {} func (*LabelPair) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{0} + return fileDescriptor_d1e5ddb18987a258, []int{0} } func (m *LabelPair) XXX_Unmarshal(b []byte) error { @@ -128,7 +137,7 @@ func (m *Gauge) Reset() { *m = Gauge{} } func (m *Gauge) String() string { return proto.CompactTextString(m) } func (*Gauge) ProtoMessage() {} func (*Gauge) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{1} + return fileDescriptor_d1e5ddb18987a258, []int{1} } func (m *Gauge) XXX_Unmarshal(b []byte) error { @@ -168,7 +177,7 @@ func (m *Counter) Reset() { *m = Counter{} } func (m *Counter) String() string { return proto.CompactTextString(m) } func (*Counter) ProtoMessage() {} func (*Counter) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{2} + return fileDescriptor_d1e5ddb18987a258, []int{2} } func (m *Counter) XXX_Unmarshal(b []byte) error { @@ -215,7 +224,7 @@ func (m *Quantile) Reset() { *m = Quantile{} } func (m *Quantile) String() string { return proto.CompactTextString(m) } func (*Quantile) ProtoMessage() {} func (*Quantile) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{3} + return fileDescriptor_d1e5ddb18987a258, []int{3} } func (m *Quantile) XXX_Unmarshal(b []byte) error { @@ -263,7 +272,7 @@ func (m *Summary) Reset() { *m = Summary{} } func (m *Summary) String() string { return proto.CompactTextString(m) } func (*Summary) ProtoMessage() {} func (*Summary) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{4} + return fileDescriptor_d1e5ddb18987a258, []int{4} } func (m *Summary) XXX_Unmarshal(b []byte) error { @@ -316,7 +325,7 @@ func (m *Untyped) Reset() { *m = Untyped{} } func (m *Untyped) String() string { return proto.CompactTextString(m) } func (*Untyped) ProtoMessage() {} func (*Untyped) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{5} + return fileDescriptor_d1e5ddb18987a258, []int{5} } func (m *Untyped) XXX_Unmarshal(b []byte) error { @@ -345,9 +354,34 @@ func (m *Untyped) GetValue() float64 { } type Histogram struct { - SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"` - SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` - Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"` + SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"` + SampleCountFloat *float64 `protobuf:"fixed64,4,opt,name=sample_count_float,json=sampleCountFloat" json:"sample_count_float,omitempty"` + SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` + // Buckets for the conventional histogram. + Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"` + // schema defines the bucket schema. Currently, valid numbers are -4 <= n <= 8. + // They are all for base-2 bucket schemas, where 1 is a bucket boundary in each case, and + // then each power of two is divided into 2^n logarithmic buckets. + // Or in other words, each bucket boundary is the previous boundary times 2^(2^-n). + // In the future, more bucket schemas may be added using numbers < -4 or > 8. + Schema *int32 `protobuf:"zigzag32,5,opt,name=schema" json:"schema,omitempty"` + ZeroThreshold *float64 `protobuf:"fixed64,6,opt,name=zero_threshold,json=zeroThreshold" json:"zero_threshold,omitempty"` + ZeroCount *uint64 `protobuf:"varint,7,opt,name=zero_count,json=zeroCount" json:"zero_count,omitempty"` + ZeroCountFloat *float64 `protobuf:"fixed64,8,opt,name=zero_count_float,json=zeroCountFloat" json:"zero_count_float,omitempty"` + // Negative buckets for the native histogram. + NegativeSpan []*BucketSpan `protobuf:"bytes,9,rep,name=negative_span,json=negativeSpan" json:"negative_span,omitempty"` + // Use either "negative_delta" or "negative_count", the former for + // regular histograms with integer counts, the latter for float + // histograms. + NegativeDelta []int64 `protobuf:"zigzag64,10,rep,name=negative_delta,json=negativeDelta" json:"negative_delta,omitempty"` + NegativeCount []float64 `protobuf:"fixed64,11,rep,name=negative_count,json=negativeCount" json:"negative_count,omitempty"` + // Positive buckets for the native histogram. + PositiveSpan []*BucketSpan `protobuf:"bytes,12,rep,name=positive_span,json=positiveSpan" json:"positive_span,omitempty"` + // Use either "positive_delta" or "positive_count", the former for + // regular histograms with integer counts, the latter for float + // histograms. + PositiveDelta []int64 `protobuf:"zigzag64,13,rep,name=positive_delta,json=positiveDelta" json:"positive_delta,omitempty"` + PositiveCount []float64 `protobuf:"fixed64,14,rep,name=positive_count,json=positiveCount" json:"positive_count,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -357,7 +391,7 @@ func (m *Histogram) Reset() { *m = Histogram{} } func (m *Histogram) String() string { return proto.CompactTextString(m) } func (*Histogram) ProtoMessage() {} func (*Histogram) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{6} + return fileDescriptor_d1e5ddb18987a258, []int{6} } func (m *Histogram) XXX_Unmarshal(b []byte) error { @@ -385,6 +419,13 @@ func (m *Histogram) GetSampleCount() uint64 { return 0 } +func (m *Histogram) GetSampleCountFloat() float64 { + if m != nil && m.SampleCountFloat != nil { + return *m.SampleCountFloat + } + return 0 +} + func (m *Histogram) GetSampleSum() float64 { if m != nil && m.SampleSum != nil { return *m.SampleSum @@ -399,8 +440,81 @@ func (m *Histogram) GetBucket() []*Bucket { return nil } +func (m *Histogram) GetSchema() int32 { + if m != nil && m.Schema != nil { + return *m.Schema + } + return 0 +} + +func (m *Histogram) GetZeroThreshold() float64 { + if m != nil && m.ZeroThreshold != nil { + return *m.ZeroThreshold + } + return 0 +} + +func (m *Histogram) GetZeroCount() uint64 { + if m != nil && m.ZeroCount != nil { + return *m.ZeroCount + } + return 0 +} + +func (m *Histogram) GetZeroCountFloat() float64 { + if m != nil && m.ZeroCountFloat != nil { + return *m.ZeroCountFloat + } + return 0 +} + +func (m *Histogram) GetNegativeSpan() []*BucketSpan { + if m != nil { + return m.NegativeSpan + } + return nil +} + +func (m *Histogram) GetNegativeDelta() []int64 { + if m != nil { + return m.NegativeDelta + } + return nil +} + +func (m *Histogram) GetNegativeCount() []float64 { + if m != nil { + return m.NegativeCount + } + return nil +} + +func (m *Histogram) GetPositiveSpan() []*BucketSpan { + if m != nil { + return m.PositiveSpan + } + return nil +} + +func (m *Histogram) GetPositiveDelta() []int64 { + if m != nil { + return m.PositiveDelta + } + return nil +} + +func (m *Histogram) GetPositiveCount() []float64 { + if m != nil { + return m.PositiveCount + } + return nil +} + +// A Bucket of a conventional histogram, each of which is treated as +// an individual counter-like time series by Prometheus. type Bucket struct { CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count,json=cumulativeCount" json:"cumulative_count,omitempty"` + CumulativeCountFloat *float64 `protobuf:"fixed64,4,opt,name=cumulative_count_float,json=cumulativeCountFloat" json:"cumulative_count_float,omitempty"` UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"` Exemplar *Exemplar `protobuf:"bytes,3,opt,name=exemplar" json:"exemplar,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -412,7 +526,7 @@ func (m *Bucket) Reset() { *m = Bucket{} } func (m *Bucket) String() string { return proto.CompactTextString(m) } func (*Bucket) ProtoMessage() {} func (*Bucket) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{7} + return fileDescriptor_d1e5ddb18987a258, []int{7} } func (m *Bucket) XXX_Unmarshal(b []byte) error { @@ -440,6 +554,13 @@ func (m *Bucket) GetCumulativeCount() uint64 { return 0 } +func (m *Bucket) GetCumulativeCountFloat() float64 { + if m != nil && m.CumulativeCountFloat != nil { + return *m.CumulativeCountFloat + } + return 0 +} + func (m *Bucket) GetUpperBound() float64 { if m != nil && m.UpperBound != nil { return *m.UpperBound @@ -454,6 +575,59 @@ func (m *Bucket) GetExemplar() *Exemplar { return nil } +// A BucketSpan defines a number of consecutive buckets in a native +// histogram with their offset. Logically, it would be more +// straightforward to include the bucket counts in the Span. However, +// the protobuf representation is more compact in the way the data is +// structured here (with all the buckets in a single array separate +// from the Spans). +type BucketSpan struct { + Offset *int32 `protobuf:"zigzag32,1,opt,name=offset" json:"offset,omitempty"` + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BucketSpan) Reset() { *m = BucketSpan{} } +func (m *BucketSpan) String() string { return proto.CompactTextString(m) } +func (*BucketSpan) ProtoMessage() {} +func (*BucketSpan) Descriptor() ([]byte, []int) { + return fileDescriptor_d1e5ddb18987a258, []int{8} +} + +func (m *BucketSpan) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BucketSpan.Unmarshal(m, b) +} +func (m *BucketSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BucketSpan.Marshal(b, m, deterministic) +} +func (m *BucketSpan) XXX_Merge(src proto.Message) { + xxx_messageInfo_BucketSpan.Merge(m, src) +} +func (m *BucketSpan) XXX_Size() int { + return xxx_messageInfo_BucketSpan.Size(m) +} +func (m *BucketSpan) XXX_DiscardUnknown() { + xxx_messageInfo_BucketSpan.DiscardUnknown(m) +} + +var xxx_messageInfo_BucketSpan proto.InternalMessageInfo + +func (m *BucketSpan) GetOffset() int32 { + if m != nil && m.Offset != nil { + return *m.Offset + } + return 0 +} + +func (m *BucketSpan) GetLength() uint32 { + if m != nil && m.Length != nil { + return *m.Length + } + return 0 +} + type Exemplar struct { Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` @@ -467,7 +641,7 @@ func (m *Exemplar) Reset() { *m = Exemplar{} } func (m *Exemplar) String() string { return proto.CompactTextString(m) } func (*Exemplar) ProtoMessage() {} func (*Exemplar) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{8} + return fileDescriptor_d1e5ddb18987a258, []int{9} } func (m *Exemplar) XXX_Unmarshal(b []byte) error { @@ -526,7 +700,7 @@ func (m *Metric) Reset() { *m = Metric{} } func (m *Metric) String() string { return proto.CompactTextString(m) } func (*Metric) ProtoMessage() {} func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{9} + return fileDescriptor_d1e5ddb18987a258, []int{10} } func (m *Metric) XXX_Unmarshal(b []byte) error { @@ -610,7 +784,7 @@ func (m *MetricFamily) Reset() { *m = MetricFamily{} } func (m *MetricFamily) String() string { return proto.CompactTextString(m) } func (*MetricFamily) ProtoMessage() {} func (*MetricFamily) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{10} + return fileDescriptor_d1e5ddb18987a258, []int{11} } func (m *MetricFamily) XXX_Unmarshal(b []byte) error { @@ -669,55 +843,72 @@ func init() { proto.RegisterType((*Untyped)(nil), "io.prometheus.client.Untyped") proto.RegisterType((*Histogram)(nil), "io.prometheus.client.Histogram") proto.RegisterType((*Bucket)(nil), "io.prometheus.client.Bucket") + proto.RegisterType((*BucketSpan)(nil), "io.prometheus.client.BucketSpan") proto.RegisterType((*Exemplar)(nil), "io.prometheus.client.Exemplar") proto.RegisterType((*Metric)(nil), "io.prometheus.client.Metric") proto.RegisterType((*MetricFamily)(nil), "io.prometheus.client.MetricFamily") } -func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) } - -var fileDescriptor_6039342a2ba47b72 = []byte{ - // 665 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0xfd, 0xdc, 0x38, 0x3f, 0xbe, 0x69, 0x3f, 0xa2, 0x51, 0x17, 0x56, 0xa1, 0x24, 0x78, 0x55, - 0x58, 0x38, 0xa2, 0x6a, 0x05, 0x2a, 0xb0, 0x68, 0x4b, 0x48, 0x91, 0x48, 0x5b, 0x26, 0xc9, 0xa2, - 0xb0, 0x88, 0x1c, 0x77, 0x70, 0x2c, 0x3c, 0xb1, 0xb1, 0x67, 0x2a, 0xb2, 0x66, 0xc1, 0x16, 0x5e, - 0x81, 0x17, 0x05, 0xcd, 0x8f, 0x6d, 0x2a, 0xb9, 0x95, 0x40, 0xec, 0x66, 0xee, 0x3d, 0xe7, 0xfa, - 0xcc, 0xf8, 0x9c, 0x81, 0x0d, 0x4a, 0x58, 0x1a, 0xfa, 0x99, 0x9b, 0xa4, 0x31, 0x8b, 0xd1, 0x66, - 0x18, 0x8b, 0x15, 0x25, 0x6c, 0x41, 0x78, 0xe6, 0xfa, 0x51, 0x48, 0x96, 0x6c, 0xab, 0x1b, 0xc4, - 0x71, 0x10, 0x91, 0xbe, 0xc4, 0xcc, 0xf9, 0x87, 0x3e, 0x0b, 0x29, 0xc9, 0x98, 0x47, 0x13, 0x45, - 0x73, 0xf6, 0xc1, 0x7a, 0xe3, 0xcd, 0x49, 0x74, 0xee, 0x85, 0x29, 0x42, 0x60, 0x2e, 0x3d, 0x4a, - 0x6c, 0xa3, 0x67, 0xec, 0x58, 0x58, 0xae, 0xd1, 0x26, 0xd4, 0xaf, 0xbc, 0x88, 0x13, 0x7b, 0x4d, - 0x16, 0xd5, 0xc6, 0xd9, 0x86, 0xfa, 0xd0, 0xe3, 0xc1, 0x6f, 0x6d, 0xc1, 0x31, 0xf2, 0xf6, 0x7b, - 0x68, 0x1e, 0xc7, 0x7c, 0xc9, 0x48, 0x5a, 0x0d, 0x40, 0x07, 0xd0, 0x22, 0x9f, 0x09, 0x4d, 0x22, - 0x2f, 0x95, 0x83, 0xdb, 0xbb, 0xf7, 0xdd, 0xaa, 0x03, 0xb8, 0x03, 0x8d, 0xc2, 0x05, 0xde, 0x79, - 0x0e, 0xad, 0xb7, 0xdc, 0x5b, 0xb2, 0x30, 0x22, 0x68, 0x0b, 0x5a, 0x9f, 0xf4, 0x5a, 0x7f, 0xa0, - 0xd8, 0x5f, 0x57, 0x5e, 0x48, 0xfb, 0x6a, 0x40, 0x73, 0xcc, 0x29, 0xf5, 0xd2, 0x15, 0x7a, 0x00, - 0xeb, 0x99, 0x47, 0x93, 0x88, 0xcc, 0x7c, 0xa1, 0x56, 0x4e, 0x30, 0x71, 0x5b, 0xd5, 0xe4, 0x01, - 0xd0, 0x36, 0x80, 0x86, 0x64, 0x9c, 0xea, 0x49, 0x96, 0xaa, 0x8c, 0x39, 0x15, 0xe7, 0x28, 0xbe, - 0x5f, 0xeb, 0xd5, 0x6e, 0x3e, 0x47, 0xae, 0xb8, 0xd4, 0xe7, 0x74, 0xa1, 0x39, 0x5d, 0xb2, 0x55, - 0x42, 0x2e, 0x6f, 0xb8, 0xc5, 0x2f, 0x06, 0x58, 0x27, 0x61, 0xc6, 0xe2, 0x20, 0xf5, 0xe8, 0x3f, - 0x10, 0xbb, 0x07, 0x8d, 0x39, 0xf7, 0x3f, 0x12, 0xa6, 0xa5, 0xde, 0xab, 0x96, 0x7a, 0x24, 0x31, - 0x58, 0x63, 0x9d, 0x6f, 0x06, 0x34, 0x54, 0x09, 0x3d, 0x84, 0x8e, 0xcf, 0x29, 0x8f, 0x3c, 0x16, - 0x5e, 0x5d, 0x97, 0x71, 0xa7, 0xac, 0x2b, 0x29, 0x5d, 0x68, 0xf3, 0x24, 0x21, 0xe9, 0x6c, 0x1e, - 0xf3, 0xe5, 0xa5, 0xd6, 0x02, 0xb2, 0x74, 0x24, 0x2a, 0xd7, 0x1c, 0x50, 0xfb, 0x43, 0x07, 0x7c, - 0x37, 0xa0, 0x95, 0x97, 0xd1, 0x3e, 0xd4, 0x23, 0xe1, 0x60, 0xdb, 0x90, 0x87, 0xea, 0x56, 0x4f, - 0x29, 0x4c, 0x8e, 0x15, 0xba, 0xda, 0x1d, 0xe8, 0x29, 0x58, 0x45, 0x42, 0xb4, 0xac, 0x2d, 0x57, - 0x65, 0xc8, 0xcd, 0x33, 0xe4, 0x4e, 0x72, 0x04, 0x2e, 0xc1, 0xce, 0xcf, 0x35, 0x68, 0x8c, 0x64, - 0x22, 0xff, 0x56, 0xd1, 0x63, 0xa8, 0x07, 0x22, 0x53, 0x3a, 0x10, 0x77, 0xab, 0x69, 0x32, 0x76, - 0x58, 0x21, 0xd1, 0x13, 0x68, 0xfa, 0x2a, 0x67, 0x5a, 0xec, 0x76, 0x35, 0x49, 0x87, 0x11, 0xe7, - 0x68, 0x41, 0xcc, 0x54, 0x08, 0x6c, 0xf3, 0x36, 0xa2, 0x4e, 0x0a, 0xce, 0xd1, 0x82, 0xc8, 0x95, - 0x69, 0xed, 0xfa, 0x6d, 0x44, 0xed, 0x6c, 0x9c, 0xa3, 0xd1, 0x0b, 0xb0, 0x16, 0xb9, 0x97, 0xed, - 0xa6, 0xa4, 0xde, 0x70, 0x31, 0x85, 0xe5, 0x71, 0xc9, 0x10, 0xee, 0x2f, 0xee, 0x7a, 0x46, 0x33, - 0xbb, 0xd1, 0x33, 0x76, 0x6a, 0xb8, 0x5d, 0xd4, 0x46, 0x99, 0xf3, 0xc3, 0x80, 0x75, 0xf5, 0x07, - 0x5e, 0x79, 0x34, 0x8c, 0x56, 0x95, 0xcf, 0x19, 0x02, 0x73, 0x41, 0xa2, 0x44, 0xbf, 0x66, 0x72, - 0x8d, 0xf6, 0xc0, 0x14, 0x1a, 0xe5, 0x15, 0xfe, 0xbf, 0xdb, 0xab, 0x56, 0xa5, 0x26, 0x4f, 0x56, - 0x09, 0xc1, 0x12, 0x2d, 0xd2, 0xa4, 0x5e, 0x60, 0xdb, 0xbc, 0x2d, 0x4d, 0x8a, 0x87, 0x35, 0xf6, - 0xd1, 0x08, 0xa0, 0x9c, 0x84, 0xda, 0xd0, 0x3c, 0x3e, 0x9b, 0x9e, 0x4e, 0x06, 0xb8, 0xf3, 0x1f, - 0xb2, 0xa0, 0x3e, 0x3c, 0x9c, 0x0e, 0x07, 0x1d, 0x43, 0xd4, 0xc7, 0xd3, 0xd1, 0xe8, 0x10, 0x5f, - 0x74, 0xd6, 0xc4, 0x66, 0x7a, 0x3a, 0xb9, 0x38, 0x1f, 0xbc, 0xec, 0xd4, 0xd0, 0x06, 0x58, 0x27, - 0xaf, 0xc7, 0x93, 0xb3, 0x21, 0x3e, 0x1c, 0x75, 0xcc, 0x23, 0x0c, 0x95, 0xef, 0xfe, 0xbb, 0x83, - 0x20, 0x64, 0x0b, 0x3e, 0x77, 0xfd, 0x98, 0xf6, 0xcb, 0x6e, 0x5f, 0x75, 0x67, 0x34, 0xbe, 0x24, - 0x51, 0x3f, 0x88, 0x9f, 0x85, 0xf1, 0xac, 0xec, 0xce, 0x54, 0xf7, 0x57, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xd0, 0x84, 0x91, 0x73, 0x59, 0x06, 0x00, 0x00, +func init() { + proto.RegisterFile("io/prometheus/client/metrics.proto", fileDescriptor_d1e5ddb18987a258) +} + +var fileDescriptor_d1e5ddb18987a258 = []byte{ + // 896 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x8e, 0xdb, 0x44, + 0x18, 0xc5, 0x9b, 0x5f, 0x7f, 0xd9, 0x6c, 0xd3, 0x61, 0x55, 0x59, 0x0b, 0xcb, 0x06, 0x4b, 0x48, + 0x0b, 0x42, 0x8e, 0x40, 0x5b, 0x81, 0x0a, 0x5c, 0xec, 0xb6, 0xe9, 0x16, 0x89, 0xb4, 0x65, 0x92, + 0x5c, 0x14, 0x2e, 0xac, 0x49, 0x32, 0xeb, 0x58, 0x78, 0x3c, 0xc6, 0x1e, 0x57, 0x2c, 0x2f, 0xc0, + 0x35, 0xaf, 0xc0, 0xc3, 0xf0, 0x22, 0x3c, 0x08, 0x68, 0xfe, 0xec, 0xdd, 0xe2, 0x94, 0xd2, 0x3b, + 0x7f, 0x67, 0xce, 0xf7, 0xcd, 0x39, 0xe3, 0xc9, 0x71, 0xc0, 0x8f, 0xf9, 0x24, 0xcb, 0x39, 0xa3, + 0x62, 0x4b, 0xcb, 0x62, 0xb2, 0x4e, 0x62, 0x9a, 0x8a, 0x09, 0xa3, 0x22, 0x8f, 0xd7, 0x45, 0x90, + 0xe5, 0x5c, 0x70, 0x74, 0x18, 0xf3, 0xa0, 0xe6, 0x04, 0x9a, 0x73, 0x74, 0x12, 0x71, 0x1e, 0x25, + 0x74, 0xa2, 0x38, 0xab, 0xf2, 0x6a, 0x22, 0x62, 0x46, 0x0b, 0x41, 0x58, 0xa6, 0xdb, 0xfc, 0xfb, + 0xe0, 0x7e, 0x47, 0x56, 0x34, 0x79, 0x4e, 0xe2, 0x1c, 0x21, 0x68, 0xa7, 0x84, 0x51, 0xcf, 0x19, + 0x3b, 0xa7, 0x2e, 0x56, 0xcf, 0xe8, 0x10, 0x3a, 0x2f, 0x49, 0x52, 0x52, 0x6f, 0x4f, 0x81, 0xba, + 0xf0, 0x8f, 0xa1, 0x73, 0x49, 0xca, 0xe8, 0xc6, 0xb2, 0xec, 0x71, 0xec, 0xf2, 0x8f, 0xd0, 0x7b, + 0xc8, 0xcb, 0x54, 0xd0, 0xbc, 0x99, 0x80, 0x1e, 0x40, 0x9f, 0xfe, 0x42, 0x59, 0x96, 0x90, 0x5c, + 0x0d, 0x1e, 0x7c, 0xfe, 0x41, 0xd0, 0x64, 0x20, 0x98, 0x1a, 0x16, 0xae, 0xf8, 0xfe, 0xd7, 0xd0, + 0xff, 0xbe, 0x24, 0xa9, 0x88, 0x13, 0x8a, 0x8e, 0xa0, 0xff, 0xb3, 0x79, 0x36, 0x1b, 0x54, 0xf5, + 0x6d, 0xe5, 0x95, 0xb4, 0xdf, 0x1c, 0xe8, 0xcd, 0x4b, 0xc6, 0x48, 0x7e, 0x8d, 0x3e, 0x84, 0xfd, + 0x82, 0xb0, 0x2c, 0xa1, 0xe1, 0x5a, 0xaa, 0x55, 0x13, 0xda, 0x78, 0xa0, 0x31, 0x65, 0x00, 0x1d, + 0x03, 0x18, 0x4a, 0x51, 0x32, 0x33, 0xc9, 0xd5, 0xc8, 0xbc, 0x64, 0xd2, 0x47, 0xb5, 0x7f, 0x6b, + 0xdc, 0xda, 0xed, 0xc3, 0x2a, 0xae, 0xf5, 0xf9, 0x27, 0xd0, 0x5b, 0xa6, 0xe2, 0x3a, 0xa3, 0x9b, + 0x1d, 0xa7, 0xf8, 0x57, 0x1b, 0xdc, 0x27, 0x71, 0x21, 0x78, 0x94, 0x13, 0xf6, 0x26, 0x62, 0x3f, + 0x05, 0x74, 0x93, 0x12, 0x5e, 0x25, 0x9c, 0x08, 0xaf, 0xad, 0x66, 0x8e, 0x6e, 0x10, 0x1f, 0x4b, + 0xfc, 0xbf, 0xac, 0x9d, 0x41, 0x77, 0x55, 0xae, 0x7f, 0xa2, 0xc2, 0x18, 0x7b, 0xbf, 0xd9, 0xd8, + 0x85, 0xe2, 0x60, 0xc3, 0x45, 0xf7, 0xa0, 0x5b, 0xac, 0xb7, 0x94, 0x11, 0xaf, 0x33, 0x76, 0x4e, + 0xef, 0x62, 0x53, 0xa1, 0x8f, 0xe0, 0xe0, 0x57, 0x9a, 0xf3, 0x50, 0x6c, 0x73, 0x5a, 0x6c, 0x79, + 0xb2, 0xf1, 0xba, 0x6a, 0xc3, 0xa1, 0x44, 0x17, 0x16, 0x94, 0x9a, 0x14, 0x4d, 0x5b, 0xec, 0x29, + 0x8b, 0xae, 0x44, 0xb4, 0xc1, 0x53, 0x18, 0xd5, 0xcb, 0xc6, 0x5e, 0x5f, 0xcd, 0x39, 0xa8, 0x48, + 0xda, 0xdc, 0x14, 0x86, 0x29, 0x8d, 0x88, 0x88, 0x5f, 0xd2, 0xb0, 0xc8, 0x48, 0xea, 0xb9, 0xca, + 0xc4, 0xf8, 0x75, 0x26, 0xe6, 0x19, 0x49, 0xf1, 0xbe, 0x6d, 0x93, 0x95, 0x94, 0x5d, 0x8d, 0xd9, + 0xd0, 0x44, 0x10, 0x0f, 0xc6, 0xad, 0x53, 0x84, 0xab, 0xe1, 0x8f, 0x24, 0x78, 0x8b, 0xa6, 0xa5, + 0x0f, 0xc6, 0x2d, 0xe9, 0xce, 0xa2, 0x5a, 0xfe, 0x14, 0x86, 0x19, 0x2f, 0xe2, 0x5a, 0xd4, 0xfe, + 0x9b, 0x8a, 0xb2, 0x6d, 0x56, 0x54, 0x35, 0x46, 0x8b, 0x1a, 0x6a, 0x51, 0x16, 0xad, 0x44, 0x55, + 0x34, 0x2d, 0xea, 0x40, 0x8b, 0xb2, 0xa8, 0x12, 0xe5, 0xff, 0xe9, 0x40, 0x57, 0x6f, 0x85, 0x3e, + 0x86, 0xd1, 0xba, 0x64, 0x65, 0x72, 0xd3, 0x88, 0xbe, 0x66, 0x77, 0x6a, 0x5c, 0x5b, 0x39, 0x83, + 0x7b, 0xaf, 0x52, 0x6f, 0x5d, 0xb7, 0xc3, 0x57, 0x1a, 0xf4, 0x5b, 0x39, 0x81, 0x41, 0x99, 0x65, + 0x34, 0x0f, 0x57, 0xbc, 0x4c, 0x37, 0xe6, 0xce, 0x81, 0x82, 0x2e, 0x24, 0x72, 0x2b, 0x17, 0x5a, + 0xff, 0x3b, 0x17, 0xa0, 0x3e, 0x32, 0x79, 0x11, 0xf9, 0xd5, 0x55, 0x41, 0xb5, 0x83, 0xbb, 0xd8, + 0x54, 0x12, 0x4f, 0x68, 0x1a, 0x89, 0xad, 0xda, 0x7d, 0x88, 0x4d, 0xe5, 0xff, 0xee, 0x40, 0xdf, + 0x0e, 0x45, 0xf7, 0xa1, 0x93, 0xc8, 0x54, 0xf4, 0x1c, 0xf5, 0x82, 0x4e, 0x9a, 0x35, 0x54, 0xc1, + 0x89, 0x35, 0xbb, 0x39, 0x71, 0xd0, 0x97, 0xe0, 0x56, 0xa9, 0x6b, 0x4c, 0x1d, 0x05, 0x3a, 0x97, + 0x03, 0x9b, 0xcb, 0xc1, 0xc2, 0x32, 0x70, 0x4d, 0xf6, 0xff, 0xde, 0x83, 0xee, 0x4c, 0xa5, 0xfc, + 0xdb, 0x2a, 0xfa, 0x0c, 0x3a, 0x91, 0xcc, 0x69, 0x13, 0xb2, 0xef, 0x35, 0xb7, 0xa9, 0x28, 0xc7, + 0x9a, 0x89, 0xbe, 0x80, 0xde, 0x5a, 0x67, 0xb7, 0x11, 0x7b, 0xdc, 0xdc, 0x64, 0x02, 0x1e, 0x5b, + 0xb6, 0x6c, 0x2c, 0x74, 0xb0, 0xaa, 0x3b, 0xb0, 0xb3, 0xd1, 0xa4, 0x2f, 0xb6, 0x6c, 0xd9, 0x58, + 0xea, 0x20, 0x54, 0xa1, 0xb1, 0xb3, 0xd1, 0xa4, 0x25, 0xb6, 0x6c, 0xf4, 0x0d, 0xb8, 0x5b, 0x9b, + 0x8f, 0x2a, 0x2c, 0x76, 0x1e, 0x4c, 0x15, 0xa3, 0xb8, 0xee, 0x90, 0x89, 0x5a, 0x9d, 0x75, 0xc8, + 0x0a, 0x95, 0x48, 0x2d, 0x3c, 0xa8, 0xb0, 0x59, 0xe1, 0xff, 0xe1, 0xc0, 0xbe, 0x7e, 0x03, 0x8f, + 0x09, 0x8b, 0x93, 0xeb, 0xc6, 0x4f, 0x24, 0x82, 0xf6, 0x96, 0x26, 0x99, 0xf9, 0x42, 0xaa, 0x67, + 0x74, 0x06, 0x6d, 0xa9, 0x51, 0x1d, 0xe1, 0xc1, 0xae, 0x5f, 0xb8, 0x9e, 0xbc, 0xb8, 0xce, 0x28, + 0x56, 0x6c, 0x99, 0xb9, 0xfa, 0xab, 0xee, 0xb5, 0x5f, 0x97, 0xb9, 0xba, 0x0f, 0x1b, 0xee, 0x27, + 0x2b, 0x80, 0x7a, 0x12, 0x1a, 0x40, 0xef, 0xe1, 0xb3, 0xe5, 0xd3, 0xc5, 0x14, 0x8f, 0xde, 0x41, + 0x2e, 0x74, 0x2e, 0xcf, 0x97, 0x97, 0xd3, 0x91, 0x23, 0xf1, 0xf9, 0x72, 0x36, 0x3b, 0xc7, 0x2f, + 0x46, 0x7b, 0xb2, 0x58, 0x3e, 0x5d, 0xbc, 0x78, 0x3e, 0x7d, 0x34, 0x6a, 0xa1, 0x21, 0xb8, 0x4f, + 0xbe, 0x9d, 0x2f, 0x9e, 0x5d, 0xe2, 0xf3, 0xd9, 0xa8, 0x8d, 0xde, 0x85, 0x3b, 0xaa, 0x27, 0xac, + 0xc1, 0xce, 0x05, 0x86, 0xc6, 0x3f, 0x18, 0x3f, 0x3c, 0x88, 0x62, 0xb1, 0x2d, 0x57, 0xc1, 0x9a, + 0xb3, 0x7f, 0xff, 0x45, 0x09, 0x19, 0xdf, 0xd0, 0x64, 0x12, 0xf1, 0xaf, 0x62, 0x1e, 0xd6, 0xab, + 0xa1, 0x5e, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0x16, 0x77, 0x81, 0x98, 0xd7, 0x08, 0x00, 0x00, } diff --git a/vendor/github.com/prometheus/common/expfmt/fuzz.go b/vendor/github.com/prometheus/common/expfmt/fuzz.go index dc2eedeef..f819e4f8b 100644 --- a/vendor/github.com/prometheus/common/expfmt/fuzz.go +++ b/vendor/github.com/prometheus/common/expfmt/fuzz.go @@ -12,6 +12,7 @@ // limitations under the License. // Build only when actually fuzzing +//go:build gofuzz // +build gofuzz package expfmt diff --git a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go index 8a9313a3b..9d94ae9ef 100644 --- a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go +++ b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go @@ -22,7 +22,6 @@ import ( "strconv" "strings" - "github.com/golang/protobuf/ptypes" "github.com/prometheus/common/model" dto "github.com/prometheus/client_model/go" @@ -473,10 +472,11 @@ func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) { if err != nil { return written, err } - ts, err := ptypes.Timestamp((*e).Timestamp) + err = (*e).Timestamp.CheckValid() if err != nil { return written, err } + ts := (*e).Timestamp.AsTime() // TODO(beorn7): Format this directly from components of ts to // avoid overflow/underflow and precision issues of the float // conversion. diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go index 7f67b16e4..c909b8aa8 100644 --- a/vendor/github.com/prometheus/common/model/time.go +++ b/vendor/github.com/prometheus/common/model/time.go @@ -193,7 +193,7 @@ func ParseDuration(durationStr string) (Duration, error) { // Allow 0 without a unit. return 0, nil case "": - return 0, fmt.Errorf("empty duration string") + return 0, errors.New("empty duration string") } matches := durationRE.FindStringSubmatch(durationStr) if matches == nil { diff --git a/vendor/github.com/prometheus/procfs/.gitignore b/vendor/github.com/prometheus/procfs/.gitignore index 25e3659ab..7cc33ae4a 100644 --- a/vendor/github.com/prometheus/procfs/.gitignore +++ b/vendor/github.com/prometheus/procfs/.gitignore @@ -1 +1,2 @@ -/fixtures/ +/testdata/fixtures/ +/fixtures diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml index 0aa09edac..a197699a1 100644 --- a/vendor/github.com/prometheus/procfs/.golangci.yml +++ b/vendor/github.com/prometheus/procfs/.golangci.yml @@ -1,4 +1,12 @@ --- linters: enable: - - golint + - godot + - revive + +linter-settings: + godot: + capital: true + exclude: + # Ignore "See: URL" + - 'See:' diff --git a/vendor/github.com/prometheus/procfs/CODE_OF_CONDUCT.md b/vendor/github.com/prometheus/procfs/CODE_OF_CONDUCT.md index 9a1aff412..d325872bd 100644 --- a/vendor/github.com/prometheus/procfs/CODE_OF_CONDUCT.md +++ b/vendor/github.com/prometheus/procfs/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ -## Prometheus Community Code of Conduct +# Prometheus Community Code of Conduct -Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). +Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). diff --git a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md index 943de7615..853eb9d49 100644 --- a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md +++ b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md @@ -97,7 +97,7 @@ Many of the files are changing continuously and the data being read can in some reads in the same file. Also, most of the files are relatively small (less than a few KBs), and system calls to the `stat` function will often return the wrong size. Therefore, for most files it's recommended to read the full file in a single operation using an internal utility function called `util.ReadFileNoStat`. -This function is similar to `ioutil.ReadFile`, but it avoids the system call to `stat` to get the current size of +This function is similar to `os.ReadFile`, but it avoids the system call to `stat` to get the current size of the file. Note that parsing the file's contents can still be performed one line at a time. This is done by first reading @@ -113,7 +113,7 @@ the full file, and then using a scanner on the `[]byte` or `string` containing t ``` The `/sys` filesystem contains many very small files which contain only a single numeric or text value. These files -can be read using an internal function called `util.SysReadFile` which is similar to `ioutil.ReadFile` but does +can be read using an internal function called `util.SysReadFile` which is similar to `os.ReadFile` but does not bother to check the size of the file before reading. ``` data, err := util.SysReadFile("/sys/class/power_supply/BAT0/capacity") diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile index fa2bd5b52..7edfe4d09 100644 --- a/vendor/github.com/prometheus/procfs/Makefile +++ b/vendor/github.com/prometheus/procfs/Makefile @@ -14,18 +14,18 @@ include Makefile.common %/.unpacked: %.ttar - @echo ">> extracting fixtures" + @echo ">> extracting fixtures $*" ./ttar -C $(dir $*) -x -f $*.ttar touch $@ -fixtures: fixtures/.unpacked +fixtures: testdata/fixtures/.unpacked update_fixtures: - rm -vf fixtures/.unpacked - ./ttar -c -f fixtures.ttar fixtures/ + rm -vf testdata/fixtures/.unpacked + ./ttar -c -f testdata/fixtures.ttar -C testdata/ fixtures/ .PHONY: build build: .PHONY: test -test: fixtures/.unpacked common-test +test: testdata/fixtures/.unpacked common-test diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common index a1b1ca40f..6c8e3e219 100644 --- a/vendor/github.com/prometheus/procfs/Makefile.common +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -36,29 +36,6 @@ GO_VERSION ?= $(shell $(GO) version) GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') -GOVENDOR := -GO111MODULE := -ifeq (, $(PRE_GO_111)) - ifneq (,$(wildcard go.mod)) - # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). - GO111MODULE := on - - ifneq (,$(wildcard vendor)) - # Always use the local vendor/ directory to satisfy the dependencies. - GOOPTS := $(GOOPTS) -mod=vendor - endif - endif -else - ifneq (,$(wildcard go.mod)) - ifneq (,$(wildcard vendor)) -$(warning This repository requires Go >= 1.11 because of Go modules) -$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') - endif - else - # This repository isn't using Go modules (yet). - GOVENDOR := $(FIRST_GOPATH)/bin/govendor - endif -endif PROMU := $(FIRST_GOPATH)/bin/promu pkgs = ./... @@ -78,17 +55,23 @@ ifneq ($(shell which gotestsum),) endif endif -PROMU_VERSION ?= 0.12.0 +PROMU_VERSION ?= 0.13.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.39.0 +GOLANGCI_LINT_VERSION ?= v1.45.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) - GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + # If we're in CI and there is an Actions file, that means the linter + # is being run in Actions, so we don't need to run it here. + ifeq (,$(CIRCLE_JOB)) + GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) + GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint + endif endif endif @@ -144,32 +127,25 @@ common-check_license: .PHONY: common-deps common-deps: @echo ">> getting dependencies" -ifdef GO111MODULE - GO111MODULE=$(GO111MODULE) $(GO) mod download -else - $(GO) get $(GOOPTS) -t ./... -endif + $(GO) mod download .PHONY: update-go-deps update-go-deps: @echo ">> updating Go dependencies" @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ - $(GO) get $$m; \ + $(GO) get -d $$m; \ done - GO111MODULE=$(GO111MODULE) $(GO) mod tidy -ifneq (,$(wildcard vendor)) - GO111MODULE=$(GO111MODULE) $(GO) mod vendor -endif + $(GO) mod tidy .PHONY: common-test-short common-test-short: $(GOTEST_DIR) @echo ">> running short tests" - GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs) + $(GOTEST) -short $(GOOPTS) $(pkgs) .PHONY: common-test common-test: $(GOTEST_DIR) @echo ">> running all tests" - GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) + $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs) $(GOTEST_DIR): @mkdir -p $@ @@ -177,25 +153,21 @@ $(GOTEST_DIR): .PHONY: common-format common-format: @echo ">> formatting code" - GO111MODULE=$(GO111MODULE) $(GO) fmt $(pkgs) + $(GO) fmt $(pkgs) .PHONY: common-vet common-vet: @echo ">> vetting code" - GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) + $(GO) vet $(GOOPTS) $(pkgs) .PHONY: common-lint common-lint: $(GOLANGCI_LINT) ifdef GOLANGCI_LINT @echo ">> running golangci-lint" -ifdef GO111MODULE # 'go list' needs to be executed before staticcheck to prepopulate the modules cache. # Otherwise staticcheck might fail randomly for some reason not yet explained. - GO111MODULE=$(GO111MODULE) $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null - GO111MODULE=$(GO111MODULE) $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) -else - $(GOLANGCI_LINT) run $(pkgs) -endif + $(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null + $(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs) endif .PHONY: common-yamllint @@ -212,28 +184,15 @@ endif common-staticcheck: lint .PHONY: common-unused -common-unused: $(GOVENDOR) -ifdef GOVENDOR - @echo ">> running check for unused packages" - @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' -else -ifdef GO111MODULE +common-unused: @echo ">> running check for unused/missing packages in go.mod" - GO111MODULE=$(GO111MODULE) $(GO) mod tidy -ifeq (,$(wildcard vendor)) + $(GO) mod tidy @git diff --exit-code -- go.sum go.mod -else - @echo ">> running check for unused packages in vendor/" - GO111MODULE=$(GO111MODULE) $(GO) mod vendor - @git diff --exit-code -- go.sum go.mod vendor/ -endif -endif -endif .PHONY: common-build common-build: promu @echo ">> building binaries" - GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) + $(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES) .PHONY: common-tarball common-tarball: promu @@ -289,12 +248,6 @@ $(GOLANGCI_LINT): | sh -s -- -b $(FIRST_GOPATH)/bin $(GOLANGCI_LINT_VERSION) endif -ifdef GOVENDOR -.PHONY: $(GOVENDOR) -$(GOVENDOR): - GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor -endif - .PHONY: precheck precheck:: diff --git a/vendor/github.com/prometheus/procfs/SECURITY.md b/vendor/github.com/prometheus/procfs/SECURITY.md index 67741f015..fed02d85c 100644 --- a/vendor/github.com/prometheus/procfs/SECURITY.md +++ b/vendor/github.com/prometheus/procfs/SECURITY.md @@ -3,4 +3,4 @@ The Prometheus security policy, including how to report vulnerabilities, can be found here: -https://prometheus.io/docs/operating/security/ + diff --git a/vendor/github.com/prometheus/procfs/arp.go b/vendor/github.com/prometheus/procfs/arp.go index 4e47e6172..68f36e888 100644 --- a/vendor/github.com/prometheus/procfs/arp.go +++ b/vendor/github.com/prometheus/procfs/arp.go @@ -15,11 +15,28 @@ package procfs import ( "fmt" - "io/ioutil" "net" + "os" + "strconv" "strings" ) +// Learned from include/uapi/linux/if_arp.h. +const ( + // completed entry (ha valid). + ATFComplete = 0x02 + // permanent entry. + ATFPermanent = 0x04 + // Publish entry. + ATFPublish = 0x08 + // Has requested trailers. + ATFUseTrailers = 0x10 + // Obsoleted: Want to use a netmask (only for proxy entries). + ATFNetmask = 0x20 + // Don't answer this addresses. + ATFDontPublish = 0x40 +) + // ARPEntry contains a single row of the columnar data represented in // /proc/net/arp. type ARPEntry struct { @@ -29,12 +46,14 @@ type ARPEntry struct { HWAddr net.HardwareAddr // Name of the device Device string + // Flags + Flags byte } // GatherARPEntries retrieves all the ARP entries, parse the relevant columns, // and then return a slice of ARPEntry's. func (fs FS) GatherARPEntries() ([]ARPEntry, error) { - data, err := ioutil.ReadFile(fs.proc.Path("net/arp")) + data, err := os.ReadFile(fs.proc.Path("net/arp")) if err != nil { return nil, fmt.Errorf("error reading arp %q: %w", fs.proc.Path("net/arp"), err) } @@ -72,14 +91,26 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) { } func parseARPEntry(columns []string) (ARPEntry, error) { + entry := ARPEntry{Device: columns[5]} ip := net.ParseIP(columns[0]) - mac := net.HardwareAddr(columns[3]) + entry.IPAddr = ip + + if mac, err := net.ParseMAC(columns[3]); err == nil { + entry.HWAddr = mac + } else { + return ARPEntry{}, err + } - entry := ARPEntry{ - IPAddr: ip, - HWAddr: mac, - Device: columns[5], + if flags, err := strconv.ParseUint(columns[2], 0, 8); err == nil { + entry.Flags = byte(flags) + } else { + return ARPEntry{}, err } return entry, nil } + +// IsComplete returns true if ARP entry is marked with complete flag. +func (entry *ARPEntry) IsComplete() bool { + return entry.Flags&ATFComplete != 0 +} diff --git a/vendor/github.com/prometheus/procfs/cpuinfo.go b/vendor/github.com/prometheus/procfs/cpuinfo.go index 5623b24a1..ff6b927da 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux // +build linux package procfs @@ -27,7 +28,7 @@ import ( "github.com/prometheus/procfs/internal/util" ) -// CPUInfo contains general information about a system CPU found in /proc/cpuinfo +// CPUInfo contains general information about a system CPU found in /proc/cpuinfo. type CPUInfo struct { Processor uint VendorID string @@ -469,7 +470,7 @@ func parseCPUInfoDummy(_ []byte) ([]CPUInfo, error) { // nolint:unused,deadcode } // firstNonEmptyLine advances the scanner to the first non-empty line -// and returns the contents of that line +// and returns the contents of that line. func firstNonEmptyLine(scanner *bufio.Scanner) string { for scanner.Scan() { line := scanner.Text() diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_armx.go b/vendor/github.com/prometheus/procfs/cpuinfo_armx.go index 44b590ed3..64cfd534c 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_armx.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_armx.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux && (arm || arm64) // +build linux // +build arm arm64 diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go b/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go index 91e272573..c11207f3a 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_mipsx.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux && (mips || mipsle || mips64 || mips64le) // +build linux // +build mips mipsle mips64 mips64le diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_others.go b/vendor/github.com/prometheus/procfs/cpuinfo_others.go index 95b5b4ec4..ea41bf2ca 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_others.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_others.go @@ -11,8 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build linux -// +build !386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x +//go:build linux && !386 && !amd64 && !arm && !arm64 && !mips && !mips64 && !mips64le && !mipsle && !ppc64 && !ppc64le && !riscv64 && !s390x +// +build linux,!386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x package procfs diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go b/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go index 6068bd571..003bc2ad4 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_ppcx.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux && (ppc64 || ppc64le) // +build linux // +build ppc64 ppc64le diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go b/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go index e83c2e207..1c9b7313b 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_riscvx.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux && (riscv || riscv64) // +build linux // +build riscv riscv64 diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go b/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go index 26814eeba..fa3686bc0 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux // +build linux package procfs diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_x86.go b/vendor/github.com/prometheus/procfs/cpuinfo_x86.go index d5bedf97f..a0ef55562 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_x86.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_x86.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux && (386 || amd64) // +build linux // +build 386 amd64 diff --git a/vendor/github.com/prometheus/procfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/fixtures.ttar deleted file mode 100644 index 5e7eeef4a..000000000 --- a/vendor/github.com/prometheus/procfs/fixtures.ttar +++ /dev/null @@ -1,7673 +0,0 @@ -# Archive created by ttar -c -f fixtures.ttar fixtures/ -Directory: fixtures -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26231 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/cmdline -Lines: 1 -vimNULLBYTEtest.goNULLBYTE+10NULLBYTEEOF -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/comm -Lines: 1 -vim -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/cwd -SymlinkTo: /usr/bin -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/environ -Lines: 1 -PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binNULLBYTEHOSTNAME=cd24e11f73a5NULLBYTETERM=xtermNULLBYTEGOLANG_VERSION=1.12.5NULLBYTEGOPATH=/goNULLBYTEHOME=/rootNULLBYTEEOF -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/exe -SymlinkTo: /usr/bin/vim -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26231/fd -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fd/0 -SymlinkTo: ../../symlinktargets/abc -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fd/1 -SymlinkTo: ../../symlinktargets/def -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fd/10 -SymlinkTo: ../../symlinktargets/xyz -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fd/2 -SymlinkTo: ../../symlinktargets/ghi -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fd/3 -SymlinkTo: ../../symlinktargets/uvw -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26231/fdinfo -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fdinfo/0 -Lines: 6 -pos: 0 -flags: 02004000 -mnt_id: 13 -inotify wd:3 ino:1 sdev:34 mask:fce ignored_mask:0 fhandle-bytes:c fhandle-type:81 f_handle:000000000100000000000000 -inotify wd:2 ino:1300016 sdev:fd00002 mask:fce ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:16003001ed3f022a -inotify wd:1 ino:2e0001 sdev:fd00000 mask:fce ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:01002e00138e7c65 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fdinfo/1 -Lines: 4 -pos: 0 -flags: 02004002 -mnt_id: 13 -eventfd-count: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fdinfo/10 -Lines: 3 -pos: 0 -flags: 02004002 -mnt_id: 9 -Mode: 400 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fdinfo/2 -Lines: 3 -pos: 0 -flags: 02004002 -mnt_id: 9 -Mode: 400 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/fdinfo/3 -Lines: 3 -pos: 0 -flags: 02004002 -mnt_id: 9 -Mode: 400 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/io -Lines: 7 -rchar: 750339 -wchar: 818609 -syscr: 7405 -syscw: 5245 -read_bytes: 1024 -write_bytes: 2048 -cancelled_write_bytes: -1024 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/limits -Lines: 17 -Limit Soft Limit Hard Limit Units -Max cpu time unlimited unlimited seconds -Max file size unlimited unlimited bytes -Max data size unlimited unlimited bytes -Max stack size 8388608 unlimited bytes -Max core file size 0 unlimited bytes -Max resident set unlimited unlimited bytes -Max processes 62898 62898 processes -Max open files 2048 4096 files -Max locked memory 18446744073708503040 18446744073708503040 bytes -Max address space 8589934592 unlimited bytes -Max file locks unlimited unlimited locks -Max pending signals 62898 62898 signals -Max msgqueue size 819200 819200 bytes -Max nice priority 0 0 -Max realtime priority 0 0 -Max realtime timeout unlimited unlimited us -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/mountstats -Lines: 20 -device rootfs mounted on / with fstype rootfs -device sysfs mounted on /sys with fstype sysfs -device proc mounted on /proc with fstype proc -device /dev/sda1 mounted on / with fstype ext4 -device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers=1.1 - opts: rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.1,clientaddr=192.168.1.5,local_lock=none - age: 13968 - caps: caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255 - nfsv4: bm0=0xfdffafff,bm1=0xf9be3e,bm2=0x0,acl=0x0,pnfs=not configured - sec: flavor=1,pseudoflavor=1 - events: 52 226 0 0 1 13 398 0 0 331 0 47 0 0 77 0 0 77 0 0 0 0 0 0 0 0 0 - bytes: 1207640230 0 0 0 1210214218 0 295483 0 - RPC iostats version: 1.0 p/v: 100003/4 (nfs) - xprt: tcp 832 0 1 0 11 6428 6428 0 12154 0 24 26 5726 - per-op statistics - NULL: 0 0 0 0 0 0 0 0 - READ: 1298 1298 0 207680 1210292152 6 79386 79407 - WRITE: 0 0 0 0 0 0 0 0 - ACCESS: 2927395007 2927394995 0 526931094212 362996810236 18446743919241604546 1667369447 1953587717 - -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26231/net -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/net/dev -Lines: 4 -Inter-| Receive | Transmit - face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed - lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - eth0: 438 5 0 0 0 0 0 0 648 8 0 0 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26231/ns -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/ns/mnt -SymlinkTo: mnt:[4026531840] -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/ns/net -SymlinkTo: net:[4026531993] -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/root -SymlinkTo: / -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/schedstat -Lines: 1 -411605849 93680043 79 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/smaps -Lines: 252 -00400000-00cb1000 r-xp 00000000 fd:01 952273 /bin/alertmanager -Size: 8900 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 2952 kB -Pss: 2952 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 2952 kB -Private_Dirty: 0 kB -Referenced: 2864 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd ex mr mw me dw sd -00cb1000-016b0000 r--p 008b1000 fd:01 952273 /bin/alertmanager -Size: 10236 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 6152 kB -Pss: 6152 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 6152 kB -Private_Dirty: 0 kB -Referenced: 5308 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd mr mw me dw sd -016b0000-0171a000 rw-p 012b0000 fd:01 952273 /bin/alertmanager -Size: 424 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 176 kB -Pss: 176 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 84 kB -Private_Dirty: 92 kB -Referenced: 176 kB -Anonymous: 92 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 12 kB -SwapPss: 12 kB -Locked: 0 kB -VmFlags: rd wr mr mw me dw ac sd -0171a000-0173f000 rw-p 00000000 00:00 0 -Size: 148 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 76 kB -Pss: 76 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 76 kB -Referenced: 76 kB -Anonymous: 76 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac sd -c000000000-c000400000 rw-p 00000000 00:00 0 -Size: 4096 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 2564 kB -Pss: 2564 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 20 kB -Private_Dirty: 2544 kB -Referenced: 2544 kB -Anonymous: 2564 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 1100 kB -SwapPss: 1100 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac sd -c000400000-c001600000 rw-p 00000000 00:00 0 -Size: 18432 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 16024 kB -Pss: 16024 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 5864 kB -Private_Dirty: 10160 kB -Referenced: 11944 kB -Anonymous: 16024 kB -LazyFree: 5848 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 440 kB -SwapPss: 440 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac sd nh -c001600000-c004000000 rw-p 00000000 00:00 0 -Size: 43008 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac sd -7f0ab95ca000-7f0abbb7b000 rw-p 00000000 00:00 0 -Size: 38596 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 1992 kB -Pss: 1992 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 476 kB -Private_Dirty: 1516 kB -Referenced: 1828 kB -Anonymous: 1992 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 384 kB -SwapPss: 384 kB -Locked: 0 kB -VmFlags: rd wr mr mw me ac sd -7ffc07ecf000-7ffc07ef0000 rw-p 00000000 00:00 0 [stack] -Size: 132 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 8 kB -Pss: 8 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 8 kB -Referenced: 8 kB -Anonymous: 8 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 4 kB -SwapPss: 4 kB -Locked: 0 kB -VmFlags: rd wr mr mw me gd ac -7ffc07f9e000-7ffc07fa1000 r--p 00000000 00:00 0 [vvar] -Size: 12 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd mr pf io de dd sd -7ffc07fa1000-7ffc07fa3000 r-xp 00000000 00:00 0 [vdso] -Size: 8 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 4 kB -Pss: 0 kB -Shared_Clean: 4 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 4 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd ex mr mw me de sd -ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] -Size: 4 kB -KernelPageSize: 4 kB -MMUPageSize: 4 kB -Rss: 0 kB -Pss: 0 kB -Shared_Clean: 0 kB -Shared_Dirty: 0 kB -Private_Clean: 0 kB -Private_Dirty: 0 kB -Referenced: 0 kB -Anonymous: 0 kB -LazyFree: 0 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 0 kB -SwapPss: 0 kB -Locked: 0 kB -VmFlags: rd ex -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/smaps_rollup -Lines: 17 -00400000-ffffffffff601000 ---p 00000000 00:00 0 [rollup] -Rss: 29948 kB -Pss: 29944 kB -Shared_Clean: 4 kB -Shared_Dirty: 0 kB -Private_Clean: 15548 kB -Private_Dirty: 14396 kB -Referenced: 24752 kB -Anonymous: 20756 kB -LazyFree: 5848 kB -AnonHugePages: 0 kB -ShmemPmdMapped: 0 kB -Shared_Hugetlb: 0 kB -Private_Hugetlb: 0 kB -Swap: 1940 kB -SwapPss: 1940 kB -Locked: 0 kB -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/stat -Lines: 1 -26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/status -Lines: 53 - -Name: prometheus -Umask: 0022 -State: S (sleeping) -Tgid: 26231 -Ngid: 0 -Pid: 26231 -PPid: 1 -TracerPid: 0 -Uid: 1000 1000 1000 0 -Gid: 1001 1001 1001 0 -FDSize: 128 -Groups: -NStgid: 1 -NSpid: 1 -NSpgid: 1 -NSsid: 1 -VmPeak: 58472 kB -VmSize: 58440 kB -VmLck: 0 kB -VmPin: 0 kB -VmHWM: 8028 kB -VmRSS: 6716 kB -RssAnon: 2092 kB -RssFile: 4624 kB -RssShmem: 0 kB -VmData: 2580 kB -VmStk: 136 kB -VmExe: 948 kB -VmLib: 6816 kB -VmPTE: 128 kB -VmPMD: 12 kB -VmSwap: 660 kB -HugetlbPages: 0 kB -Threads: 1 -SigQ: 8/63965 -SigPnd: 0000000000000000 -ShdPnd: 0000000000000000 -SigBlk: 7be3c0fe28014a03 -SigIgn: 0000000000001000 -SigCgt: 00000001800004ec -CapInh: 0000000000000000 -CapPrm: 0000003fffffffff -CapEff: 0000003fffffffff -CapBnd: 0000003fffffffff -CapAmb: 0000000000000000 -Seccomp: 0 -Cpus_allowed: ff -Cpus_allowed_list: 0-7 -Mems_allowed: 00000000,00000001 -Mems_allowed_list: 0 -voluntary_ctxt_switches: 4742839 -nonvoluntary_ctxt_switches: 1727500 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26231/wchan -Lines: 1 -poll_schedule_timeoutEOF -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26232 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/cmdline -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/comm -Lines: 1 -ata_sff -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/cwd -SymlinkTo: /does/not/exist -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26232/fd -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/fd/0 -SymlinkTo: ../../symlinktargets/abc -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/fd/1 -SymlinkTo: ../../symlinktargets/def -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/fd/2 -SymlinkTo: ../../symlinktargets/ghi -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/fd/3 -SymlinkTo: ../../symlinktargets/uvw -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/fd/4 -SymlinkTo: ../../symlinktargets/xyz -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/limits -Lines: 17 -Limit Soft Limit Hard Limit Units -Max cpu time unlimited unlimited seconds -Max file size unlimited unlimited bytes -Max data size unlimited unlimited bytes -Max stack size 8388608 unlimited bytes -Max core file size 0 unlimited bytes -Max resident set unlimited unlimited bytes -Max processes 29436 29436 processes -Max open files 1024 4096 files -Max locked memory 65536 65536 bytes -Max address space unlimited unlimited bytes -Max file locks unlimited unlimited locks -Max pending signals 29436 29436 signals -Max msgqueue size 819200 819200 bytes -Max nice priority 0 0 -Max realtime priority 0 0 -Max realtime timeout unlimited unlimited us -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/maps -Lines: 9 -55680ae1e000-55680ae20000 r--p 00000000 fd:01 47316994 /bin/cat -55680ae29000-55680ae2a000 rwxs 0000a000 fd:01 47316994 /bin/cat -55680bed6000-55680bef7000 rw-p 00000000 00:00 0 [heap] -7fdf964fc000-7fdf973f2000 r--p 00000000 fd:01 17432624 /usr/lib/locale/locale-archive -7fdf973f2000-7fdf97417000 r--p 00000000 fd:01 60571062 /lib/x86_64-linux-gnu/libc-2.29.so -7ffe9215c000-7ffe9217f000 rw-p 00000000 00:00 0 [stack] -7ffe921da000-7ffe921dd000 r--p 00000000 00:00 0 [vvar] -7ffe921dd000-7ffe921de000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall] -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/root -SymlinkTo: /does/not/exist -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/stat -Lines: 1 -33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26232/wchan -Lines: 1 -0EOF -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26233 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26233/cmdline -Lines: 1 -com.github.uiautomatorNULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTEEOF -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26233/schedstat -Lines: 8 - ____________________________________ -< this is a malformed schedstat file > - ------------------------------------ - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/26234 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/26234/maps -Lines: 4 -08048000-08089000 r-xp 00000000 03:01 104219 /bin/tcsh -08089000-0808c000 rw-p 00041000 03:01 104219 /bin/tcsh -0808c000-08146000 rwxp 00000000 00:00 0 -40000000-40015000 r-xp 00000000 03:01 61874 /lib/ld-2.3.2.so -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/584 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/584/stat -Lines: 2 -1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0 -#!/bin/cat /proc/self/stat -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/buddyinfo -Lines: 3 -Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3 -Node 0, zone DMA32 759 572 791 475 194 45 12 0 0 0 0 -Node 0, zone Normal 4381 1093 185 1530 567 102 4 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/cmdline -Lines: 1 -BOOT_IMAGE=/vmlinuz-5.11.0-22-generic root=UUID=456a0345-450d-4f7b-b7c9-43e3241d99ad ro quiet splash vt.handoff=7 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/cpuinfo -Lines: 216 -processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 799.998 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 0 -cpu cores : 4 -apicid : 0 -initial apicid : 0 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 1 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 800.037 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 1 -cpu cores : 4 -apicid : 2 -initial apicid : 2 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 2 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 800.010 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 2 -cpu cores : 4 -apicid : 4 -initial apicid : 4 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 3 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 800.028 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 3 -cpu cores : 4 -apicid : 6 -initial apicid : 6 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 4 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 799.989 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 0 -cpu cores : 4 -apicid : 1 -initial apicid : 1 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 5 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 800.083 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 1 -cpu cores : 4 -apicid : 3 -initial apicid : 3 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 6 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 800.017 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 2 -cpu cores : 4 -apicid : 5 -initial apicid : 5 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -processor : 7 -vendor_id : GenuineIntel -cpu family : 6 -model : 142 -model name : Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz -stepping : 10 -microcode : 0xb4 -cpu MHz : 800.030 -cache size : 8192 KB -physical id : 0 -siblings : 8 -core id : 3 -cpu cores : 4 -apicid : 7 -initial apicid : 7 -fpu : yes -fpu_exception : yes -cpuid level : 22 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d -bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs -bogomips : 4224.00 -clflush size : 64 -cache_alignment : 64 -address sizes : 39 bits physical, 48 bits virtual -power management: - -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/crypto -Lines: 972 -name : ccm(aes) -driver : ccm_base(ctr(aes-aesni),cbcmac(aes-aesni)) -module : ccm -priority : 300 -refcnt : 4 -selftest : passed -internal : no -type : aead -async : no -blocksize : 1 -ivsize : 16 -maxauthsize : 16 -geniv : - -name : cbcmac(aes) -driver : cbcmac(aes-aesni) -module : ccm -priority : 300 -refcnt : 7 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 16 - -name : ecdh -driver : ecdh-generic -module : ecdh_generic -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : kpp -async : yes - -name : ecb(arc4) -driver : ecb(arc4)-generic -module : arc4 -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : no -blocksize : 1 -min keysize : 1 -max keysize : 256 -ivsize : 0 -chunksize : 1 -walksize : 1 - -name : arc4 -driver : arc4-generic -module : arc4 -priority : 0 -refcnt : 3 -selftest : passed -internal : no -type : cipher -blocksize : 1 -min keysize : 1 -max keysize : 256 - -name : crct10dif -driver : crct10dif-pclmul -module : crct10dif_pclmul -priority : 200 -refcnt : 2 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 2 - -name : crc32 -driver : crc32-pclmul -module : crc32_pclmul -priority : 200 -refcnt : 1 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 4 - -name : __ghash -driver : cryptd(__ghash-pclmulqdqni) -module : kernel -priority : 50 -refcnt : 1 -selftest : passed -internal : yes -type : ahash -async : yes -blocksize : 16 -digestsize : 16 - -name : ghash -driver : ghash-clmulni -module : ghash_clmulni_intel -priority : 400 -refcnt : 1 -selftest : passed -internal : no -type : ahash -async : yes -blocksize : 16 -digestsize : 16 - -name : __ghash -driver : __ghash-pclmulqdqni -module : ghash_clmulni_intel -priority : 0 -refcnt : 1 -selftest : passed -internal : yes -type : shash -blocksize : 16 -digestsize : 16 - -name : crc32c -driver : crc32c-intel -module : crc32c_intel -priority : 200 -refcnt : 5 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 4 - -name : cbc(aes) -driver : cbc(aes-aesni) -module : kernel -priority : 300 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : no -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : ctr(aes) -driver : ctr(aes-aesni) -module : kernel -priority : 300 -refcnt : 5 -selftest : passed -internal : no -type : skcipher -async : no -blocksize : 1 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : pkcs1pad(rsa,sha256) -driver : pkcs1pad(rsa-generic,sha256) -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : akcipher - -name : __xts(aes) -driver : cryptd(__xts-aes-aesni) -module : kernel -priority : 451 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : yes -blocksize : 16 -min keysize : 32 -max keysize : 64 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : xts(aes) -driver : xts-aes-aesni -module : kernel -priority : 401 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : yes -blocksize : 16 -min keysize : 32 -max keysize : 64 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : __ctr(aes) -driver : cryptd(__ctr-aes-aesni) -module : kernel -priority : 450 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : yes -blocksize : 1 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : ctr(aes) -driver : ctr-aes-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : yes -blocksize : 1 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : __cbc(aes) -driver : cryptd(__cbc-aes-aesni) -module : kernel -priority : 450 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : yes -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : cbc(aes) -driver : cbc-aes-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : yes -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : __ecb(aes) -driver : cryptd(__ecb-aes-aesni) -module : kernel -priority : 450 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : yes -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 0 -chunksize : 16 -walksize : 16 - -name : ecb(aes) -driver : ecb-aes-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : yes -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 0 -chunksize : 16 -walksize : 16 - -name : __generic-gcm-aes-aesni -driver : cryptd(__driver-generic-gcm-aes-aesni) -module : kernel -priority : 50 -refcnt : 1 -selftest : passed -internal : yes -type : aead -async : yes -blocksize : 1 -ivsize : 12 -maxauthsize : 16 -geniv : - -name : gcm(aes) -driver : generic-gcm-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : no -type : aead -async : yes -blocksize : 1 -ivsize : 12 -maxauthsize : 16 -geniv : - -name : __generic-gcm-aes-aesni -driver : __driver-generic-gcm-aes-aesni -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : yes -type : aead -async : no -blocksize : 1 -ivsize : 12 -maxauthsize : 16 -geniv : - -name : __gcm-aes-aesni -driver : cryptd(__driver-gcm-aes-aesni) -module : kernel -priority : 50 -refcnt : 1 -selftest : passed -internal : yes -type : aead -async : yes -blocksize : 1 -ivsize : 8 -maxauthsize : 16 -geniv : - -name : rfc4106(gcm(aes)) -driver : rfc4106-gcm-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : no -type : aead -async : yes -blocksize : 1 -ivsize : 8 -maxauthsize : 16 -geniv : - -name : __gcm-aes-aesni -driver : __driver-gcm-aes-aesni -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : yes -type : aead -async : no -blocksize : 1 -ivsize : 8 -maxauthsize : 16 -geniv : - -name : __xts(aes) -driver : __xts-aes-aesni -module : kernel -priority : 401 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : no -blocksize : 16 -min keysize : 32 -max keysize : 64 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : __ctr(aes) -driver : __ctr-aes-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : no -blocksize : 1 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : __cbc(aes) -driver : __cbc-aes-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : no -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 16 -chunksize : 16 -walksize : 16 - -name : __ecb(aes) -driver : __ecb-aes-aesni -module : kernel -priority : 400 -refcnt : 1 -selftest : passed -internal : yes -type : skcipher -async : no -blocksize : 16 -min keysize : 16 -max keysize : 32 -ivsize : 0 -chunksize : 16 -walksize : 16 - -name : __aes -driver : __aes-aesni -module : kernel -priority : 300 -refcnt : 1 -selftest : passed -internal : yes -type : cipher -blocksize : 16 -min keysize : 16 -max keysize : 32 - -name : aes -driver : aes-aesni -module : kernel -priority : 300 -refcnt : 8 -selftest : passed -internal : no -type : cipher -blocksize : 16 -min keysize : 16 -max keysize : 32 - -name : hmac(sha1) -driver : hmac(sha1-generic) -module : kernel -priority : 100 -refcnt : 9 -selftest : passed -internal : no -type : shash -blocksize : 64 -digestsize : 20 - -name : ghash -driver : ghash-generic -module : kernel -priority : 100 -refcnt : 3 -selftest : passed -internal : no -type : shash -blocksize : 16 -digestsize : 16 - -name : jitterentropy_rng -driver : jitterentropy_rng -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_hmac_sha256 -module : kernel -priority : 221 -refcnt : 2 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_hmac_sha512 -module : kernel -priority : 220 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_hmac_sha384 -module : kernel -priority : 219 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_hmac_sha1 -module : kernel -priority : 218 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_sha256 -module : kernel -priority : 217 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_sha512 -module : kernel -priority : 216 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_sha384 -module : kernel -priority : 215 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_sha1 -module : kernel -priority : 214 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_ctr_aes256 -module : kernel -priority : 213 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_ctr_aes192 -module : kernel -priority : 212 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_nopr_ctr_aes128 -module : kernel -priority : 211 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : hmac(sha256) -driver : hmac(sha256-generic) -module : kernel -priority : 100 -refcnt : 10 -selftest : passed -internal : no -type : shash -blocksize : 64 -digestsize : 32 - -name : stdrng -driver : drbg_pr_hmac_sha256 -module : kernel -priority : 210 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_hmac_sha512 -module : kernel -priority : 209 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_hmac_sha384 -module : kernel -priority : 208 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_hmac_sha1 -module : kernel -priority : 207 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_sha256 -module : kernel -priority : 206 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_sha512 -module : kernel -priority : 205 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_sha384 -module : kernel -priority : 204 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_sha1 -module : kernel -priority : 203 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_ctr_aes256 -module : kernel -priority : 202 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_ctr_aes192 -module : kernel -priority : 201 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : stdrng -driver : drbg_pr_ctr_aes128 -module : kernel -priority : 200 -refcnt : 1 -selftest : passed -internal : no -type : rng -seedsize : 0 - -name : 842 -driver : 842-scomp -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : scomp - -name : 842 -driver : 842-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : compression - -name : lzo-rle -driver : lzo-rle-scomp -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : scomp - -name : lzo-rle -driver : lzo-rle-generic -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : compression - -name : lzo -driver : lzo-scomp -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : scomp - -name : lzo -driver : lzo-generic -module : kernel -priority : 0 -refcnt : 9 -selftest : passed -internal : no -type : compression - -name : crct10dif -driver : crct10dif-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 2 - -name : crc32c -driver : crc32c-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 4 - -name : zlib-deflate -driver : zlib-deflate-scomp -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : scomp - -name : deflate -driver : deflate-scomp -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : scomp - -name : deflate -driver : deflate-generic -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : compression - -name : aes -driver : aes-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : cipher -blocksize : 16 -min keysize : 16 -max keysize : 32 - -name : sha224 -driver : sha224-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : shash -blocksize : 64 -digestsize : 28 - -name : sha256 -driver : sha256-generic -module : kernel -priority : 100 -refcnt : 11 -selftest : passed -internal : no -type : shash -blocksize : 64 -digestsize : 32 - -name : sha1 -driver : sha1-generic -module : kernel -priority : 100 -refcnt : 11 -selftest : passed -internal : no -type : shash -blocksize : 64 -digestsize : 20 - -name : md5 -driver : md5-generic -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : shash -blocksize : 64 -digestsize : 16 - -name : ecb(cipher_null) -driver : ecb-cipher_null -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : skcipher -async : no -blocksize : 1 -min keysize : 0 -max keysize : 0 -ivsize : 0 -chunksize : 1 -walksize : 1 - -name : digest_null -driver : digest_null-generic -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : shash -blocksize : 1 -digestsize : 0 - -name : compress_null -driver : compress_null-generic -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : compression - -name : cipher_null -driver : cipher_null-generic -module : kernel -priority : 0 -refcnt : 1 -selftest : passed -internal : no -type : cipher -blocksize : 1 -min keysize : 0 -max keysize : 0 - -name : rsa -driver : rsa-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : akcipher - -name : dh -driver : dh-generic -module : kernel -priority : 100 -refcnt : 1 -selftest : passed -internal : no -type : kpp - -name : aes -driver : aes-asm -module : kernel -priority : 200 -refcnt : 1 -selftest : passed -internal : no -type : cipher -blocksize : 16 -min keysize : 16 -max keysize : 32 - -Mode: 444 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/diskstats -Lines: 52 - 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 - 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 - 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 - 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 - 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 - 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 - 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 - 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 - 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 - 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 - 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 - 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 - 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 - 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 - 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 - 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 - 7 0 loop0 0 0 0 0 0 0 0 0 0 0 0 - 7 1 loop1 0 0 0 0 0 0 0 0 0 0 0 - 7 2 loop2 0 0 0 0 0 0 0 0 0 0 0 - 7 3 loop3 0 0 0 0 0 0 0 0 0 0 0 - 7 4 loop4 0 0 0 0 0 0 0 0 0 0 0 - 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 - 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 - 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 - 8 0 sda 25354637 34367663 1003346126 18492372 28444756 11134226 505697032 63877960 0 9653880 82621804 - 8 1 sda1 250 0 2000 36 0 0 0 0 0 36 36 - 8 2 sda2 246 0 1968 32 0 0 0 0 0 32 32 - 8 3 sda3 340 13 2818 52 11 8 152 8 0 56 60 - 8 4 sda4 25353629 34367650 1003337964 18492232 27448755 11134218 505696880 61593380 0 7576432 80332428 - 252 0 dm-0 59910002 0 1003337218 46229572 39231014 0 505696880 1158557800 0 11325968 1206301256 - 252 1 dm-1 388 0 3104 84 74 0 592 0 0 76 84 - 252 2 dm-2 11571 0 308350 6536 153522 0 5093416 122884 0 65400 129416 - 252 3 dm-3 3870 0 3870 104 0 0 0 0 0 16 104 - 252 4 dm-4 392 0 1034 28 38 0 137 16 0 24 44 - 252 5 dm-5 3729 0 84279 924 98918 0 1151688 104684 0 58848 105632 - 179 0 mmcblk0 192 3 1560 156 0 0 0 0 0 136 156 - 179 1 mmcblk0p1 17 3 160 24 0 0 0 0 0 24 24 - 179 2 mmcblk0p2 95 0 760 68 0 0 0 0 0 68 68 - 2 0 fd0 2 0 16 80 0 0 0 0 0 80 80 - 254 0 vda 1775784 15386 32670882 8655768 6038856 20711856 213637440 2069221364 0 41614592 2077872228 - 254 1 vda1 668 85 5984 956 207 4266 35784 32772 0 8808 33720 - 254 2 vda2 1774936 15266 32663262 8654692 5991028 20707590 213601656 2069152216 0 41607628 2077801992 - 11 0 sr0 0 0 0 0 0 0 0 0 0 0 0 - 259 0 nvme0n1 47114 4 4643973 21650 1078320 43950 39451633 1011053 0 222766 1032546 - 259 1 nvme0n1p1 1140 0 9370 16 1 0 1 0 0 16 16 - 259 2 nvme0n1p2 45914 4 4631243 21626 1036885 43950 39451632 919480 0 131580 940970 - 8 0 sdb 326552 841 9657779 84 41822 2895 1972905 5007 0 60730 67070 68851 0 1925173784 11130 - 8 1 sdb1 231 3 34466 4 24 23 106 0 0 64 64 0 0 0 0 - 8 2 sdb2 326310 838 9622281 67 40726 2872 1972799 4924 0 58250 64567 68851 0 1925173784 11130 - 8 0 sdc 14202 71 579164 21861 2995 1589 180500 40875 0 11628 55200 0 0 0 0 127 182 - 8 1 sdc1 1027 0 13795 5021 2 0 4096 3 0 690 4579 0 0 0 0 0 0 - 8 2 sdc2 13126 71 561749 16802 2830 1589 176404 40620 0 10931 50449 0 0 0 0 0 0 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/fs -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/fs/fscache -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/fs/fscache/stats -Lines: 24 -FS-Cache statistics -Cookies: idx=3 dat=67877 spc=0 -Objects: alc=67473 nal=0 avl=67473 ded=388 -ChkAux : non=12 ok=33 upd=44 obs=55 -Pages : mrk=547164 unc=364577 -Acquire: n=67880 nul=98 noc=25 ok=67780 nbf=39 oom=26 -Lookups: n=67473 neg=67470 pos=58 crt=67473 tmo=85 -Invals : n=14 run=13 -Updates: n=7 nul=3 run=8 -Relinqs: n=394 nul=1 wcr=2 rtr=3 -AttrChg: n=6 ok=5 nbf=4 oom=3 run=2 -Allocs : n=20 ok=19 wt=18 nbf=17 int=16 -Allocs : ops=15 owt=14 abt=13 -Retrvls: n=151959 ok=82823 wt=23467 nod=69136 nbf=15 int=69 oom=43 -Retrvls: ops=151959 owt=42747 abt=44 -Stores : n=225565 ok=225565 agn=12 nbf=13 oom=14 -Stores : ops=69156 run=294721 pgs=225565 rxd=225565 olm=43 -VmScan : nos=364512 gon=2 bsy=43 can=12 wt=66 -Ops : pend=42753 run=221129 enq=628798 can=11 rej=88 -Ops : ini=377538 dfr=27 rel=377538 gc=37 -CacheOp: alo=1 luo=2 luc=3 gro=4 -CacheOp: inv=5 upo=6 dro=7 pto=8 atc=9 syn=10 -CacheOp: rap=11 ras=12 alp=13 als=14 wrp=15 ucp=16 dsp=17 -CacheEv: nsp=18 stl=19 rtr=20 cul=21EOF -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/fs/xfs -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/fs/xfs/stat -Lines: 23 -extent_alloc 92447 97589 92448 93751 -abt 0 0 0 0 -blk_map 1767055 188820 184891 92447 92448 2140766 0 -bmbt 0 0 0 0 -dir 185039 92447 92444 136422 -trans 706 944304 0 -ig 185045 58807 0 126238 0 33637 22 -log 2883 113448 9 17360 739 -push_ail 945014 0 134260 15483 0 3940 464 159985 0 40 -xstrat 92447 0 -rw 107739 94045 -attr 4 0 0 0 -icluster 8677 7849 135802 -vnodes 92601 0 0 0 92444 92444 92444 0 -buf 2666287 7122 2659202 3599 2 7085 0 10297 7085 -abtb2 184941 1277345 13257 13278 0 0 0 0 0 0 0 0 0 0 2746147 -abtc2 345295 2416764 172637 172658 0 0 0 0 0 0 0 0 0 0 21406023 -bmbt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -ibt2 343004 1358467 0 0 0 0 0 0 0 0 0 0 0 0 0 -fibt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -qm 0 0 0 0 0 0 0 0 -xpc 399724544 92823103 86219234 -debug 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/loadavg -Lines: 1 -0.02 0.04 0.05 1/497 11947 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/mdstat -Lines: 60 -Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10] - -md3 : active raid6 sda1[8] sdh1[7] sdg1[6] sdf1[5] sde1[11] sdd1[3] sdc1[10] sdb1[9] sdd1[10](S) sdd2[11](S) - 5853468288 blocks super 1.2 level 6, 64k chunk, algorithm 2 [8/8] [UUUUUUUU] - -md127 : active raid1 sdi2[0] sdj2[1] - 312319552 blocks [2/2] [UU] - -md0 : active raid1 sdi1[0] sdj1[1] - 248896 blocks [2/2] [UU] - -md4 : inactive raid1 sda3[0](F) sdb3[1](S) - 4883648 blocks [2/2] [UU] - -md6 : active raid1 sdb2[2](F) sdc[1](S) sda2[0] - 195310144 blocks [2/1] [U_] - [=>...................] recovery = 8.5% (16775552/195310144) finish=17.0min speed=259783K/sec - -md8 : active raid1 sdb1[1] sda1[0] sdc[2](S) sde[3](S) - 195310144 blocks [2/2] [UU] - [=>...................] resync = 8.5% (16775552/195310144) finish=17.0min speed=259783K/sec - -md201 : active raid1 sda3[0] sdb3[1] - 1993728 blocks super 1.2 [2/2] [UU] - [=>...................] check = 5.7% (114176/1993728) finish=0.2min speed=114176K/sec - -md7 : active raid6 sdb1[0] sde1[3] sdd1[2] sdc1[1](F) - 7813735424 blocks super 1.2 level 6, 512k chunk, algorithm 2 [4/3] [U_UU] - bitmap: 0/30 pages [0KB], 65536KB chunk - -md9 : active raid1 sdc2[2] sdd2[3] sdb2[1] sda2[0] sde[4](F) sdf[5](F) sdg[6](S) - 523968 blocks super 1.2 [4/4] [UUUU] - resync=DELAYED - -md10 : active raid0 sda1[0] sdb1[1] - 314159265 blocks 64k chunks - -md11 : active (auto-read-only) raid1 sdb2[0] sdc2[1] sdc3[2](F) hda[4](S) ssdc2[3](S) - 4190208 blocks super 1.2 [2/2] [UU] - resync=PENDING - -md12 : active raid0 sdc2[0] sdd2[1] - 3886394368 blocks super 1.2 512k chunks - -md126 : active raid0 sdb[1] sdc[0] - 1855870976 blocks super external:/md127/0 128k chunks - -md219 : inactive sdb[2](S) sdc[1](S) sda[0](S) - 7932 blocks super external:imsm - -md00 : active raid0 xvdb[0] - 4186624 blocks super 1.2 256k chunks - -md120 : active linear sda1[1] sdb1[0] - 2095104 blocks super 1.2 0k rounding - -md101 : active (read-only) raid0 sdb[2] sdd[1] sdc[0] - 322560 blocks super 1.2 512k chunks - -unused devices: -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/meminfo -Lines: 42 -MemTotal: 15666184 kB -MemFree: 440324 kB -Buffers: 1020128 kB -Cached: 12007640 kB -SwapCached: 0 kB -Active: 6761276 kB -Inactive: 6532708 kB -Active(anon): 267256 kB -Inactive(anon): 268 kB -Active(file): 6494020 kB -Inactive(file): 6532440 kB -Unevictable: 0 kB -Mlocked: 0 kB -SwapTotal: 0 kB -SwapFree: 0 kB -Dirty: 768 kB -Writeback: 0 kB -AnonPages: 266216 kB -Mapped: 44204 kB -Shmem: 1308 kB -Slab: 1807264 kB -SReclaimable: 1738124 kB -SUnreclaim: 69140 kB -KernelStack: 1616 kB -PageTables: 5288 kB -NFS_Unstable: 0 kB -Bounce: 0 kB -WritebackTmp: 0 kB -CommitLimit: 7833092 kB -Committed_AS: 530844 kB -VmallocTotal: 34359738367 kB -VmallocUsed: 36596 kB -VmallocChunk: 34359637840 kB -HardwareCorrupted: 0 kB -AnonHugePages: 12288 kB -HugePages_Total: 0 -HugePages_Free: 0 -HugePages_Rsvd: 0 -HugePages_Surp: 0 -Hugepagesize: 2048 kB -DirectMap4k: 91136 kB -DirectMap2M: 16039936 kB -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/net -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/arp -Lines: 2 -IP address HW type Flags HW address Mask Device -192.168.224.1 0x1 0x2 00:50:56:c0:00:08 * ens33 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/dev -Lines: 6 -Inter-| Receive | Transmit - face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed -vethf345468: 648 8 0 0 0 0 0 0 438 5 0 0 0 0 0 0 - lo: 1664039048 1566805 0 0 0 0 0 0 1664039048 1566805 0 0 0 0 0 0 -docker0: 2568 38 0 0 0 0 0 0 438 5 0 0 0 0 0 0 - eth0: 874354587 1036395 0 0 0 0 0 0 563352563 732147 0 0 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/ip_vs -Lines: 21 -IP Virtual Server version 1.2.1 (size=4096) -Prot LocalAddress:Port Scheduler Flags - -> RemoteAddress:Port Forward Weight ActiveConn InActConn -TCP C0A80016:0CEA wlc - -> C0A85216:0CEA Tunnel 100 248 2 - -> C0A85318:0CEA Tunnel 100 248 2 - -> C0A85315:0CEA Tunnel 100 248 1 -TCP C0A80039:0CEA wlc - -> C0A85416:0CEA Tunnel 0 0 0 - -> C0A85215:0CEA Tunnel 100 1499 0 - -> C0A83215:0CEA Tunnel 100 1498 0 -TCP C0A80037:0CEA wlc - -> C0A8321A:0CEA Tunnel 0 0 0 - -> C0A83120:0CEA Tunnel 100 0 0 -TCP [2620:0000:0000:0000:0000:0000:0000:0001]:0050 sh - -> [2620:0000:0000:0000:0000:0000:0000:0002]:0050 Route 1 0 0 - -> [2620:0000:0000:0000:0000:0000:0000:0003]:0050 Route 1 0 0 - -> [2620:0000:0000:0000:0000:0000:0000:0004]:0050 Route 1 1 1 -FWM 10001000 wlc - -> C0A8321A:0CEA Route 0 0 1 - -> C0A83215:0CEA Route 0 0 2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/ip_vs_stats -Lines: 6 - Total Incoming Outgoing Incoming Outgoing - Conns Packets Packets Bytes Bytes - 16AA370 E33656E5 0 51D8C8883AB3 0 - - Conns/s Pkts/s Pkts/s Bytes/s Bytes/s - 4 1FB3C 0 1282A8F 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/protocols -Lines: 14 -protocol size sockets memory press maxhdr slab module cl co di ac io in de sh ss gs se re sp bi br ha uh gp em -PACKET 1344 2 -1 NI 0 no kernel n n n n n n n n n n n n n n n n n n n -PINGv6 1112 0 -1 NI 0 yes kernel y y y n n y n n y y y y n y y y y y n -RAWv6 1112 1 -1 NI 0 yes kernel y y y n y y y n y y y y n y y y y n n -UDPLITEv6 1216 0 57 NI 0 yes kernel y y y n y y y n y y y y n n n y y y n -UDPv6 1216 10 57 NI 0 yes kernel y y y n y y y n y y y y n n n y y y n -TCPv6 2144 1937 1225378 no 320 yes kernel y y y y y y y y y y y y y n y y y y y -UNIX 1024 120 -1 NI 0 yes kernel n n n n n n n n n n n n n n n n n n n -UDP-Lite 1024 0 57 NI 0 yes kernel y y y n y y y n y y y y y n n y y y n -PING 904 0 -1 NI 0 yes kernel y y y n n y n n y y y y n y y y y y n -RAW 912 0 -1 NI 0 yes kernel y y y n y y y n y y y y n y y y y n n -UDP 1024 73 57 NI 0 yes kernel y y y n y y y n y y y y y n n y y y n -TCP 1984 93064 1225378 yes 320 yes kernel y y y y y y y y y y y y y n y y y y y -NETLINK 1040 16 -1 NI 0 no kernel n n n n n n n n n n n n n n n n n n n -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/net/rpc -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/rpc/nfs -Lines: 5 -net 18628 0 18628 6 -rpc 4329785 0 4338291 -proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 -proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 0 241 4 4 2 39 -proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/rpc/nfsd -Lines: 11 -rc 0 6 18622 -fh 0 0 0 0 0 -io 157286400 0 -th 8 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 -ra 32 0 0 0 0 0 0 0 0 0 0 0 -net 18628 0 18628 6 -rpc 18628 0 0 0 0 -proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 -proc3 22 2 112 0 2719 111 0 0 0 0 0 0 0 0 0 0 0 27 216 0 2 1 0 -proc4 2 2 10853 -proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/sockstat -Lines: 6 -sockets: used 1602 -TCP: inuse 35 orphan 0 tw 4 alloc 59 mem 22 -UDP: inuse 12 mem 62 -UDPLITE: inuse 0 -RAW: inuse 0 -FRAG: inuse 0 memory 0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/sockstat6 -Lines: 5 -TCP6: inuse 17 -UDP6: inuse 9 -UDPLITE6: inuse 0 -RAW6: inuse 1 -FRAG6: inuse 0 memory 0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/softnet_stat -Lines: 2 -00015c73 00020e76 F0000769 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 -01663fb2 00000000 000109a4 00000000 00000000 00000000 00000000 00000000 00000000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/softnet_stat.broken -Lines: 1 -00015c73 00020e76 F0000769 00000000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/net/stat -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/stat/arp_cache -Lines: 3 -entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls -00000014 00000001 00000002 00000003 00000004 00000005 00000006 00000007 00000008 00000009 0000000a 0000000b 0000000c -00000014 0000000d 0000000e 0000000f 00000010 00000011 00000012 00000013 00000014 00000015 00000016 00000017 00000018 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/stat/ndisc_cache -Lines: 3 -entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls -00000024 000000f0 000000f1 000000f2 000000f3 000000f4 000000f5 000000f6 000000f7 000000f8 000000f9 000000fa 000000fb -00000024 000000fc 000000fd 000000fe 000000ff 00000100 00000101 00000102 00000103 00000104 00000105 00000106 00000107 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/tcp -Lines: 4 - sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode - 0: 0500000A:0016 00000000:0000 0A 00000000:00000001 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 - 1: 00000000:0016 00000000:0000 0A 00000001:00000000 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 - 2: 00000000:0016 00000000:0000 0A 00000001:00000001 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/tcp6 -Lines: 3 - sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops - 1315: 00000000000000000000000000000000:14EB 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 981 0 21040 2 0000000013726323 0 - 6073: 000080FE00000000FFADE15609667CFE:C781 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 1000 0 11337031 2 00000000b9256fdd 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/udp -Lines: 4 - sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode - 0: 0500000A:0016 00000000:0000 0A 00000000:00000001 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 - 1: 00000000:0016 00000000:0000 0A 00000001:00000000 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 - 2: 00000000:0016 00000000:0000 0A 00000001:00000001 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/udp6 -Lines: 3 - sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops - 1315: 00000000000000000000000000000000:14EB 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 981 0 21040 2 0000000013726323 0 - 6073: 000080FE00000000FFADE15609667CFE:C781 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 1000 0 11337031 2 00000000b9256fdd 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/udp_broken -Lines: 2 - sl local_address rem_address st - 1: 00000000:0016 00000000:0000 0A -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/unix -Lines: 6 -Num RefCount Protocol Flags Type St Inode Path -0000000000000000: 00000002 00000000 00010000 0001 01 3442596 /var/run/postgresql/.s.PGSQL.5432 -0000000000000000: 0000000a 00000000 00010000 0005 01 10061 /run/udev/control -0000000000000000: 00000007 00000000 00000000 0002 01 12392 /dev/log -0000000000000000: 00000003 00000000 00000000 0001 03 4787297 /var/run/postgresql/.s.PGSQL.5432 -0000000000000000: 00000003 00000000 00000000 0001 03 5091797 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/unix_without_inode -Lines: 6 -Num RefCount Protocol Flags Type St Path -0000000000000000: 00000002 00000000 00010000 0001 01 /var/run/postgresql/.s.PGSQL.5432 -0000000000000000: 0000000a 00000000 00010000 0005 01 /run/udev/control -0000000000000000: 00000007 00000000 00000000 0002 01 /dev/log -0000000000000000: 00000003 00000000 00000000 0001 03 /var/run/postgresql/.s.PGSQL.5432 -0000000000000000: 00000003 00000000 00000000 0001 03 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/net/xfrm_stat -Lines: 28 -XfrmInError 1 -XfrmInBufferError 2 -XfrmInHdrError 4 -XfrmInNoStates 3 -XfrmInStateProtoError 40 -XfrmInStateModeError 100 -XfrmInStateSeqError 6000 -XfrmInStateExpired 4 -XfrmInStateMismatch 23451 -XfrmInStateInvalid 55555 -XfrmInTmplMismatch 51 -XfrmInNoPols 65432 -XfrmInPolBlock 100 -XfrmInPolError 10000 -XfrmOutError 1000000 -XfrmOutBundleGenError 43321 -XfrmOutBundleCheckError 555 -XfrmOutNoStates 869 -XfrmOutStateProtoError 4542 -XfrmOutStateModeError 4 -XfrmOutStateSeqError 543 -XfrmOutStateExpired 565 -XfrmOutPolBlock 43456 -XfrmOutPolDead 7656 -XfrmOutPolError 1454 -XfrmFwdHdrError 6654 -XfrmOutStateInvalid 28765 -XfrmAcquireError 24532 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/pressure -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/pressure/cpu -Lines: 1 -some avg10=0.10 avg60=2.00 avg300=3.85 total=15 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/pressure/io -Lines: 2 -some avg10=0.10 avg60=2.00 avg300=3.85 total=15 -full avg10=0.20 avg60=3.00 avg300=4.95 total=25 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/pressure/memory -Lines: 2 -some avg10=0.10 avg60=2.00 avg300=3.85 total=15 -full avg10=0.20 avg60=3.00 avg300=4.95 total=25 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/schedstat -Lines: 6 -version 15 -timestamp 15819019232 -cpu0 498494191 0 3533438552 2553969831 3853684107 2465731542 2045936778163039 343796328169361 4767485306 -domain0 00000000,00000003 212499247 210112015 1861015 1860405436 536440 369895 32599 210079416 25368550 24241256 384652 927363878 807233 6366 1647 24239609 2122447165 1886868564 121112060 2848625533 125678146 241025 1032026 1885836538 2545 12 2533 0 0 0 0 0 0 1387952561 21076581 0 -cpu1 518377256 0 4155211005 2778589869 10466382 2867629021 1904686152592476 364107263788241 5145567945 -domain0 00000000,00000003 217653037 215526982 1577949 1580427380 557469 393576 28538 215498444 28721913 27662819 371153 870843407 745912 5523 1639 27661180 2331056874 2107732788 111442342 652402556 123615235 196159 1045245 2106687543 2400 3 2397 0 0 0 0 0 0 1437804657 26220076 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/self -SymlinkTo: 26231 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/slabinfo -Lines: 302 -slabinfo - version: 2.1 -# name : tunables : slabdata -pid_3 375 532 576 28 4 : tunables 0 0 0 : slabdata 19 19 0 -pid_2 3 28 576 28 4 : tunables 0 0 0 : slabdata 1 1 0 -nvidia_p2p_page_cache 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -nvidia_pte_cache 9022 9152 368 22 2 : tunables 0 0 0 : slabdata 416 416 0 -nvidia_stack_cache 321 326 12624 2 8 : tunables 0 0 0 : slabdata 163 163 0 -kvm_async_pf 0 0 472 34 4 : tunables 0 0 0 : slabdata 0 0 0 -kvm_vcpu 0 0 15552 2 8 : tunables 0 0 0 : slabdata 0 0 0 -kvm_mmu_page_header 0 0 504 32 4 : tunables 0 0 0 : slabdata 0 0 0 -pte_list_desc 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -x86_emulator 0 0 3024 10 8 : tunables 0 0 0 : slabdata 0 0 0 -x86_fpu 0 0 4608 7 8 : tunables 0 0 0 : slabdata 0 0 0 -iwl_cmd_pool:0000:04:00.0 0 128 512 32 4 : tunables 0 0 0 : slabdata 4 4 0 -ext4_groupinfo_4k 3719 3740 480 34 4 : tunables 0 0 0 : slabdata 110 110 0 -bio-6 32 75 640 25 4 : tunables 0 0 0 : slabdata 3 3 0 -bio-5 16 48 1344 24 8 : tunables 0 0 0 : slabdata 2 2 0 -bio-4 17 92 1408 23 8 : tunables 0 0 0 : slabdata 4 4 0 -fat_inode_cache 0 0 1056 31 8 : tunables 0 0 0 : slabdata 0 0 0 -fat_cache 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -ovl_aio_req 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -ovl_inode 0 0 1000 32 8 : tunables 0 0 0 : slabdata 0 0 0 -squashfs_inode_cache 0 0 1088 30 8 : tunables 0 0 0 : slabdata 0 0 0 -fuse_request 0 0 472 34 4 : tunables 0 0 0 : slabdata 0 0 0 -fuse_inode 0 0 1152 28 8 : tunables 0 0 0 : slabdata 0 0 0 -xfs_dqtrx 0 0 864 37 8 : tunables 0 0 0 : slabdata 0 0 0 -xfs_dquot 0 0 832 39 8 : tunables 0 0 0 : slabdata 0 0 0 -xfs_buf 0 0 768 21 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_bui_item 0 0 544 30 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_bud_item 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_cui_item 0 0 768 21 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_cud_item 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_rui_item 0 0 1024 32 8 : tunables 0 0 0 : slabdata 0 0 0 -xfs_rud_item 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_icr 0 0 520 31 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_ili 0 0 528 31 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_inode 0 0 1344 24 8 : tunables 0 0 0 : slabdata 0 0 0 -xfs_efi_item 0 0 768 21 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_efd_item 0 0 776 21 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_buf_item 0 0 608 26 4 : tunables 0 0 0 : slabdata 0 0 0 -xf_trans 0 0 568 28 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_ifork 0 0 376 21 2 : tunables 0 0 0 : slabdata 0 0 0 -xfs_da_state 0 0 816 20 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_btree_cur 0 0 560 29 4 : tunables 0 0 0 : slabdata 0 0 0 -xfs_bmap_free_item 0 0 400 20 2 : tunables 0 0 0 : slabdata 0 0 0 -xfs_log_ticket 0 0 520 31 4 : tunables 0 0 0 : slabdata 0 0 0 -nfs_direct_cache 0 0 560 29 4 : tunables 0 0 0 : slabdata 0 0 0 -nfs_commit_data 4 28 1152 28 8 : tunables 0 0 0 : slabdata 1 1 0 -nfs_write_data 32 50 1280 25 8 : tunables 0 0 0 : slabdata 2 2 0 -nfs_read_data 0 0 1280 25 8 : tunables 0 0 0 : slabdata 0 0 0 -nfs_inode_cache 0 0 1408 23 8 : tunables 0 0 0 : slabdata 0 0 0 -nfs_page 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -rpc_inode_cache 0 0 1024 32 8 : tunables 0 0 0 : slabdata 0 0 0 -rpc_buffers 8 13 2496 13 8 : tunables 0 0 0 : slabdata 1 1 0 -rpc_tasks 8 25 640 25 4 : tunables 0 0 0 : slabdata 1 1 0 -fscache_cookie_jar 1 35 464 35 4 : tunables 0 0 0 : slabdata 1 1 0 -jfs_mp 32 35 464 35 4 : tunables 0 0 0 : slabdata 1 1 0 -jfs_ip 0 0 1592 20 8 : tunables 0 0 0 : slabdata 0 0 0 -reiser_inode_cache 0 0 1096 29 8 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_end_io_wq 0 0 464 35 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_prelim_ref 0 0 424 38 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_delayed_extent_op 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_delayed_data_ref 0 0 448 36 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_delayed_tree_ref 0 0 440 37 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_delayed_ref_head 0 0 480 34 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_inode_defrag 0 0 400 20 2 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_delayed_node 0 0 648 25 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_ordered_extent 0 0 752 21 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_extent_map 0 0 480 34 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_extent_state 0 0 416 39 4 : tunables 0 0 0 : slabdata 0 0 0 -bio-3 35 92 704 23 4 : tunables 0 0 0 : slabdata 4 4 0 -btrfs_extent_buffer 0 0 600 27 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_free_space_bitmap 0 0 12288 2 8 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_free_space 0 0 416 39 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_path 0 0 448 36 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_trans_handle 0 0 440 37 4 : tunables 0 0 0 : slabdata 0 0 0 -btrfs_inode 0 0 1496 21 8 : tunables 0 0 0 : slabdata 0 0 0 -ext4_inode_cache 84136 84755 1400 23 8 : tunables 0 0 0 : slabdata 3685 3685 0 -ext4_free_data 22 80 392 20 2 : tunables 0 0 0 : slabdata 4 4 0 -ext4_allocation_context 0 70 464 35 4 : tunables 0 0 0 : slabdata 2 2 0 -ext4_prealloc_space 24 74 440 37 4 : tunables 0 0 0 : slabdata 2 2 0 -ext4_system_zone 267 273 376 21 2 : tunables 0 0 0 : slabdata 13 13 0 -ext4_io_end_vec 0 88 368 22 2 : tunables 0 0 0 : slabdata 4 4 0 -ext4_io_end 0 80 400 20 2 : tunables 0 0 0 : slabdata 4 4 0 -ext4_bio_post_read_ctx 128 147 384 21 2 : tunables 0 0 0 : slabdata 7 7 0 -ext4_pending_reservation 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -ext4_extent_status 79351 79422 376 21 2 : tunables 0 0 0 : slabdata 3782 3782 0 -jbd2_transaction_s 44 100 640 25 4 : tunables 0 0 0 : slabdata 4 4 0 -jbd2_inode 6785 6840 400 20 2 : tunables 0 0 0 : slabdata 342 342 0 -jbd2_journal_handle 0 80 392 20 2 : tunables 0 0 0 : slabdata 4 4 0 -jbd2_journal_head 824 1944 448 36 4 : tunables 0 0 0 : slabdata 54 54 0 -jbd2_revoke_table_s 4 23 352 23 2 : tunables 0 0 0 : slabdata 1 1 0 -jbd2_revoke_record_s 0 156 416 39 4 : tunables 0 0 0 : slabdata 4 4 0 -ext2_inode_cache 0 0 1144 28 8 : tunables 0 0 0 : slabdata 0 0 0 -mbcache 0 0 392 20 2 : tunables 0 0 0 : slabdata 0 0 0 -dm_thin_new_mapping 0 152 424 38 4 : tunables 0 0 0 : slabdata 4 4 0 -dm_snap_pending_exception 0 0 464 35 4 : tunables 0 0 0 : slabdata 0 0 0 -dm_exception 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -dm_dirty_log_flush_entry 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -dm_bio_prison_cell_v2 0 0 432 37 4 : tunables 0 0 0 : slabdata 0 0 0 -dm_bio_prison_cell 0 148 432 37 4 : tunables 0 0 0 : slabdata 4 4 0 -kcopyd_job 0 8 3648 8 8 : tunables 0 0 0 : slabdata 1 1 0 -io 0 32 512 32 4 : tunables 0 0 0 : slabdata 1 1 0 -dm_uevent 0 0 3224 10 8 : tunables 0 0 0 : slabdata 0 0 0 -dax_cache 1 28 1152 28 8 : tunables 0 0 0 : slabdata 1 1 0 -aic94xx_ascb 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -aic94xx_dma_token 0 0 384 21 2 : tunables 0 0 0 : slabdata 0 0 0 -asd_sas_event 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -sas_task 0 0 704 23 4 : tunables 0 0 0 : slabdata 0 0 0 -qla2xxx_srbs 0 0 832 39 8 : tunables 0 0 0 : slabdata 0 0 0 -sd_ext_cdb 2 22 368 22 2 : tunables 0 0 0 : slabdata 1 1 0 -scsi_sense_cache 258 288 512 32 4 : tunables 0 0 0 : slabdata 9 9 0 -virtio_scsi_cmd 64 75 640 25 4 : tunables 0 0 0 : slabdata 3 3 0 -L2TP/IPv6 0 0 1536 21 8 : tunables 0 0 0 : slabdata 0 0 0 -L2TP/IP 0 0 1408 23 8 : tunables 0 0 0 : slabdata 0 0 0 -ip6-frags 0 0 520 31 4 : tunables 0 0 0 : slabdata 0 0 0 -fib6_nodes 5 32 512 32 4 : tunables 0 0 0 : slabdata 1 1 0 -ip6_dst_cache 4 25 640 25 4 : tunables 0 0 0 : slabdata 1 1 0 -ip6_mrt_cache 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -PINGv6 0 0 1600 20 8 : tunables 0 0 0 : slabdata 0 0 0 -RAWv6 25 40 1600 20 8 : tunables 0 0 0 : slabdata 2 2 0 -UDPLITEv6 0 0 1728 18 8 : tunables 0 0 0 : slabdata 0 0 0 -UDPv6 3 54 1728 18 8 : tunables 0 0 0 : slabdata 3 3 0 -tw_sock_TCPv6 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -request_sock_TCPv6 0 0 632 25 4 : tunables 0 0 0 : slabdata 0 0 0 -TCPv6 0 33 2752 11 8 : tunables 0 0 0 : slabdata 3 3 0 -uhci_urb_priv 0 0 392 20 2 : tunables 0 0 0 : slabdata 0 0 0 -sgpool-128 2 14 4544 7 8 : tunables 0 0 0 : slabdata 2 2 0 -sgpool-64 2 13 2496 13 8 : tunables 0 0 0 : slabdata 1 1 0 -sgpool-32 2 44 1472 22 8 : tunables 0 0 0 : slabdata 2 2 0 -sgpool-16 2 68 960 34 8 : tunables 0 0 0 : slabdata 2 2 0 -sgpool-8 2 46 704 23 4 : tunables 0 0 0 : slabdata 2 2 0 -btree_node 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -bfq_io_cq 0 0 488 33 4 : tunables 0 0 0 : slabdata 0 0 0 -bfq_queue 0 0 848 38 8 : tunables 0 0 0 : slabdata 0 0 0 -mqueue_inode_cache 1 24 1344 24 8 : tunables 0 0 0 : slabdata 1 1 0 -isofs_inode_cache 0 0 968 33 8 : tunables 0 0 0 : slabdata 0 0 0 -io_kiocb 0 0 640 25 4 : tunables 0 0 0 : slabdata 0 0 0 -kioctx 0 30 1088 30 8 : tunables 0 0 0 : slabdata 1 1 0 -aio_kiocb 0 28 576 28 4 : tunables 0 0 0 : slabdata 1 1 0 -userfaultfd_ctx_cache 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -fanotify_path_event 0 0 392 20 2 : tunables 0 0 0 : slabdata 0 0 0 -fanotify_fid_event 0 0 400 20 2 : tunables 0 0 0 : slabdata 0 0 0 -fsnotify_mark 0 0 408 20 2 : tunables 0 0 0 : slabdata 0 0 0 -dnotify_mark 0 0 416 39 4 : tunables 0 0 0 : slabdata 0 0 0 -dnotify_struct 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -dio 0 0 1088 30 8 : tunables 0 0 0 : slabdata 0 0 0 -bio-2 4 25 640 25 4 : tunables 0 0 0 : slabdata 1 1 0 -fasync_cache 0 0 384 21 2 : tunables 0 0 0 : slabdata 0 0 0 -audit_tree_mark 0 0 416 39 4 : tunables 0 0 0 : slabdata 0 0 0 -pid_namespace 30 34 480 34 4 : tunables 0 0 0 : slabdata 1 1 0 -posix_timers_cache 0 27 592 27 4 : tunables 0 0 0 : slabdata 1 1 0 -iommu_devinfo 24 32 512 32 4 : tunables 0 0 0 : slabdata 1 1 0 -iommu_domain 10 10 3264 10 8 : tunables 0 0 0 : slabdata 1 1 0 -iommu_iova 8682 8748 448 36 4 : tunables 0 0 0 : slabdata 243 243 0 -UNIX 529 814 1472 22 8 : tunables 0 0 0 : slabdata 37 37 0 -ip4-frags 0 0 536 30 4 : tunables 0 0 0 : slabdata 0 0 0 -ip_mrt_cache 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -UDP-Lite 0 0 1536 21 8 : tunables 0 0 0 : slabdata 0 0 0 -tcp_bind_bucket 7 128 512 32 4 : tunables 0 0 0 : slabdata 4 4 0 -inet_peer_cache 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -xfrm_dst_cache 0 0 704 23 4 : tunables 0 0 0 : slabdata 0 0 0 -xfrm_state 0 0 1152 28 8 : tunables 0 0 0 : slabdata 0 0 0 -ip_fib_trie 7 21 384 21 2 : tunables 0 0 0 : slabdata 1 1 0 -ip_fib_alias 9 20 392 20 2 : tunables 0 0 0 : slabdata 1 1 0 -ip_dst_cache 27 84 576 28 4 : tunables 0 0 0 : slabdata 3 3 0 -PING 0 0 1408 23 8 : tunables 0 0 0 : slabdata 0 0 0 -RAW 32 46 1408 23 8 : tunables 0 0 0 : slabdata 2 2 0 -UDP 11 168 1536 21 8 : tunables 0 0 0 : slabdata 8 8 0 -tw_sock_TCP 1 56 576 28 4 : tunables 0 0 0 : slabdata 2 2 0 -request_sock_TCP 0 25 632 25 4 : tunables 0 0 0 : slabdata 1 1 0 -TCP 10 60 2624 12 8 : tunables 0 0 0 : slabdata 5 5 0 -hugetlbfs_inode_cache 2 35 928 35 8 : tunables 0 0 0 : slabdata 1 1 0 -dquot 0 0 640 25 4 : tunables 0 0 0 : slabdata 0 0 0 -bio-1 32 46 704 23 4 : tunables 0 0 0 : slabdata 2 2 0 -eventpoll_pwq 409 600 408 20 2 : tunables 0 0 0 : slabdata 30 30 0 -eventpoll_epi 408 672 576 28 4 : tunables 0 0 0 : slabdata 24 24 0 -inotify_inode_mark 58 195 416 39 4 : tunables 0 0 0 : slabdata 5 5 0 -scsi_data_buffer 0 0 360 22 2 : tunables 0 0 0 : slabdata 0 0 0 -bio_crypt_ctx 128 147 376 21 2 : tunables 0 0 0 : slabdata 7 7 0 -request_queue 29 39 2408 13 8 : tunables 0 0 0 : slabdata 3 3 0 -blkdev_ioc 81 148 440 37 4 : tunables 0 0 0 : slabdata 4 4 0 -bio-0 125 200 640 25 4 : tunables 0 0 0 : slabdata 8 8 0 -biovec-max 166 196 4544 7 8 : tunables 0 0 0 : slabdata 28 28 0 -biovec-128 0 52 2496 13 8 : tunables 0 0 0 : slabdata 4 4 0 -biovec-64 0 88 1472 22 8 : tunables 0 0 0 : slabdata 4 4 0 -biovec-16 0 92 704 23 4 : tunables 0 0 0 : slabdata 4 4 0 -bio_integrity_payload 4 28 576 28 4 : tunables 0 0 0 : slabdata 1 1 0 -khugepaged_mm_slot 59 180 448 36 4 : tunables 0 0 0 : slabdata 5 5 0 -ksm_mm_slot 0 0 384 21 2 : tunables 0 0 0 : slabdata 0 0 0 -ksm_stable_node 0 0 400 20 2 : tunables 0 0 0 : slabdata 0 0 0 -ksm_rmap_item 0 0 400 20 2 : tunables 0 0 0 : slabdata 0 0 0 -user_namespace 2 37 864 37 8 : tunables 0 0 0 : slabdata 1 1 0 -uid_cache 5 28 576 28 4 : tunables 0 0 0 : slabdata 1 1 0 -dmaengine-unmap-256 1 13 2496 13 8 : tunables 0 0 0 : slabdata 1 1 0 -dmaengine-unmap-128 1 22 1472 22 8 : tunables 0 0 0 : slabdata 1 1 0 -dmaengine-unmap-16 1 28 576 28 4 : tunables 0 0 0 : slabdata 1 1 0 -dmaengine-unmap-2 1 36 448 36 4 : tunables 0 0 0 : slabdata 1 1 0 -audit_buffer 0 22 360 22 2 : tunables 0 0 0 : slabdata 1 1 0 -sock_inode_cache 663 1170 1216 26 8 : tunables 0 0 0 : slabdata 45 45 0 -skbuff_ext_cache 0 0 576 28 4 : tunables 0 0 0 : slabdata 0 0 0 -skbuff_fclone_cache 1 72 896 36 8 : tunables 0 0 0 : slabdata 2 2 0 -skbuff_head_cache 3 650 640 25 4 : tunables 0 0 0 : slabdata 26 26 0 -configfs_dir_cache 7 38 424 38 4 : tunables 0 0 0 : slabdata 1 1 0 -file_lock_cache 27 116 552 29 4 : tunables 0 0 0 : slabdata 4 4 0 -file_lock_ctx 106 120 392 20 2 : tunables 0 0 0 : slabdata 6 6 0 -fsnotify_mark_connector 52 66 368 22 2 : tunables 0 0 0 : slabdata 3 3 0 -net_namespace 1 6 5312 6 8 : tunables 0 0 0 : slabdata 1 1 0 -task_delay_info 784 1560 416 39 4 : tunables 0 0 0 : slabdata 40 40 0 -taskstats 45 92 688 23 4 : tunables 0 0 0 : slabdata 4 4 0 -proc_dir_entry 678 682 528 31 4 : tunables 0 0 0 : slabdata 22 22 0 -pde_opener 0 189 376 21 2 : tunables 0 0 0 : slabdata 9 9 0 -proc_inode_cache 7150 8250 992 33 8 : tunables 0 0 0 : slabdata 250 250 0 -seq_file 60 735 456 35 4 : tunables 0 0 0 : slabdata 21 21 0 -sigqueue 0 156 416 39 4 : tunables 0 0 0 : slabdata 4 4 0 -bdev_cache 36 78 1216 26 8 : tunables 0 0 0 : slabdata 3 3 0 -shmem_inode_cache 1599 2208 1016 32 8 : tunables 0 0 0 : slabdata 69 69 0 -kernfs_iattrs_cache 1251 1254 424 38 4 : tunables 0 0 0 : slabdata 33 33 0 -kernfs_node_cache 52898 52920 464 35 4 : tunables 0 0 0 : slabdata 1512 1512 0 -mnt_cache 42 46 704 23 4 : tunables 0 0 0 : slabdata 2 2 0 -filp 4314 6371 704 23 4 : tunables 0 0 0 : slabdata 277 277 0 -inode_cache 28695 29505 920 35 8 : tunables 0 0 0 : slabdata 843 843 0 -dentry 166069 169074 528 31 4 : tunables 0 0 0 : slabdata 5454 5454 0 -names_cache 0 35 4544 7 8 : tunables 0 0 0 : slabdata 5 5 0 -hashtab_node 0 0 360 22 2 : tunables 0 0 0 : slabdata 0 0 0 -ebitmap_node 0 0 400 20 2 : tunables 0 0 0 : slabdata 0 0 0 -avtab_extended_perms 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -avtab_node 0 0 360 22 2 : tunables 0 0 0 : slabdata 0 0 0 -avc_xperms_data 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -avc_xperms_decision_node 0 0 384 21 2 : tunables 0 0 0 : slabdata 0 0 0 -avc_xperms_node 0 0 392 20 2 : tunables 0 0 0 : slabdata 0 0 0 -avc_node 37 40 408 20 2 : tunables 0 0 0 : slabdata 2 2 0 -iint_cache 0 0 448 36 4 : tunables 0 0 0 : slabdata 0 0 0 -lsm_inode_cache 122284 122340 392 20 2 : tunables 0 0 0 : slabdata 6117 6117 0 -lsm_file_cache 4266 4485 352 23 2 : tunables 0 0 0 : slabdata 195 195 0 -key_jar 8 25 640 25 4 : tunables 0 0 0 : slabdata 1 1 0 -buffer_head 255622 257076 440 37 4 : tunables 0 0 0 : slabdata 6948 6948 0 -uts_namespace 0 0 776 21 4 : tunables 0 0 0 : slabdata 0 0 0 -nsproxy 31 40 408 20 2 : tunables 0 0 0 : slabdata 2 2 0 -vm_area_struct 39115 43214 528 31 4 : tunables 0 0 0 : slabdata 1394 1394 0 -mm_struct 96 529 1408 23 8 : tunables 0 0 0 : slabdata 23 23 0 -fs_cache 102 756 448 36 4 : tunables 0 0 0 : slabdata 21 21 0 -files_cache 102 588 1152 28 8 : tunables 0 0 0 : slabdata 21 21 0 -signal_cache 266 672 1536 21 8 : tunables 0 0 0 : slabdata 32 32 0 -sighand_cache 266 507 2496 13 8 : tunables 0 0 0 : slabdata 39 39 0 -task_struct 783 963 10240 3 8 : tunables 0 0 0 : slabdata 321 321 0 -cred_jar 364 952 576 28 4 : tunables 0 0 0 : slabdata 34 34 0 -anon_vma_chain 63907 67821 416 39 4 : tunables 0 0 0 : slabdata 1739 1739 0 -anon_vma 25891 28899 416 39 4 : tunables 0 0 0 : slabdata 741 741 0 -pid 408 992 512 32 4 : tunables 0 0 0 : slabdata 31 31 0 -Acpi-Operand 6682 6740 408 20 2 : tunables 0 0 0 : slabdata 337 337 0 -Acpi-ParseExt 0 39 416 39 4 : tunables 0 0 0 : slabdata 1 1 0 -Acpi-Parse 0 80 392 20 2 : tunables 0 0 0 : slabdata 4 4 0 -Acpi-State 0 78 416 39 4 : tunables 0 0 0 : slabdata 2 2 0 -Acpi-Namespace 3911 3948 384 21 2 : tunables 0 0 0 : slabdata 188 188 0 -trace_event_file 2638 2660 424 38 4 : tunables 0 0 0 : slabdata 70 70 0 -ftrace_event_field 6592 6594 384 21 2 : tunables 0 0 0 : slabdata 314 314 0 -pool_workqueue 41 64 1024 32 8 : tunables 0 0 0 : slabdata 2 2 0 -radix_tree_node 21638 24045 912 35 8 : tunables 0 0 0 : slabdata 687 687 0 -task_group 48 78 1216 26 8 : tunables 0 0 0 : slabdata 3 3 0 -vmap_area 4411 4680 400 20 2 : tunables 0 0 0 : slabdata 234 234 0 -dma-kmalloc-8k 0 0 24576 1 8 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-4k 0 0 12288 2 8 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-2k 0 0 6144 5 8 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-1k 0 0 3072 10 8 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-512 0 0 1536 21 8 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-256 0 0 1024 32 8 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-128 0 0 640 25 4 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-64 0 0 512 32 4 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-32 0 0 416 39 4 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-16 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-8 0 0 344 23 2 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-192 0 0 528 31 4 : tunables 0 0 0 : slabdata 0 0 0 -dma-kmalloc-96 0 0 432 37 4 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-8k 0 0 24576 1 8 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-4k 0 0 12288 2 8 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-2k 0 0 6144 5 8 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-1k 0 0 3072 10 8 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-512 0 0 1536 21 8 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-256 0 0 1024 32 8 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-192 0 0 528 31 4 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-128 31 75 640 25 4 : tunables 0 0 0 : slabdata 3 3 0 -kmalloc-rcl-96 3371 3626 432 37 4 : tunables 0 0 0 : slabdata 98 98 0 -kmalloc-rcl-64 2080 2272 512 32 4 : tunables 0 0 0 : slabdata 71 71 0 -kmalloc-rcl-32 0 0 416 39 4 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-16 0 0 368 22 2 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-rcl-8 0 0 344 23 2 : tunables 0 0 0 : slabdata 0 0 0 -kmalloc-8k 133 140 24576 1 8 : tunables 0 0 0 : slabdata 140 140 0 -kmalloc-4k 403 444 12288 2 8 : tunables 0 0 0 : slabdata 222 222 0 -kmalloc-2k 2391 2585 6144 5 8 : tunables 0 0 0 : slabdata 517 517 0 -kmalloc-1k 2163 2420 3072 10 8 : tunables 0 0 0 : slabdata 242 242 0 -kmalloc-512 2972 3633 1536 21 8 : tunables 0 0 0 : slabdata 173 173 0 -kmalloc-256 1841 1856 1024 32 8 : tunables 0 0 0 : slabdata 58 58 0 -kmalloc-192 2165 2914 528 31 4 : tunables 0 0 0 : slabdata 94 94 0 -kmalloc-128 1137 1175 640 25 4 : tunables 0 0 0 : slabdata 47 47 0 -kmalloc-96 1925 2590 432 37 4 : tunables 0 0 0 : slabdata 70 70 0 -kmalloc-64 9433 10688 512 32 4 : tunables 0 0 0 : slabdata 334 334 0 -kmalloc-32 9098 10062 416 39 4 : tunables 0 0 0 : slabdata 258 258 0 -kmalloc-16 10914 10956 368 22 2 : tunables 0 0 0 : slabdata 498 498 0 -kmalloc-8 7576 7705 344 23 2 : tunables 0 0 0 : slabdata 335 335 0 -kmem_cache_node 904 928 512 32 4 : tunables 0 0 0 : slabdata 29 29 0 -kmem_cache 904 936 832 39 8 : tunables 0 0 0 : slabdata 24 24 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/stat -Lines: 16 -cpu 301854 612 111922 8979004 3552 2 3944 0 0 0 -cpu0 44490 19 21045 1087069 220 1 3410 0 0 0 -cpu1 47869 23 16474 1110787 591 0 46 0 0 0 -cpu2 46504 36 15916 1112321 441 0 326 0 0 0 -cpu3 47054 102 15683 1113230 533 0 60 0 0 0 -cpu4 28413 25 10776 1140321 217 0 8 0 0 0 -cpu5 29271 101 11586 1136270 672 0 30 0 0 0 -cpu6 29152 36 10276 1139721 319 0 29 0 0 0 -cpu7 29098 268 10164 1139282 555 0 31 0 0 0 -intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 0 0 0 231237 0 0 0 0 250586 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223424 190745 13 906 1283803 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -ctxt 38014093 -btime 1418183276 -processes 26442 -procs_running 2 -procs_blocked 1 -softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/swaps -Lines: 2 -Filename Type Size Used Priority -/dev/dm-2 partition 131068 176 -2 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/symlinktargets -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/symlinktargets/README -Lines: 2 -This directory contains some empty files that are the symlinks the files in the "fd" directory point to. -They are otherwise ignored by the tests -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/symlinktargets/abc -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/symlinktargets/def -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/symlinktargets/ghi -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/symlinktargets/uvw -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/symlinktargets/xyz -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/sys -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/sys/kernel -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/sys/kernel/random -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/kernel/random/entropy_avail -Lines: 1 -3943 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/kernel/random/poolsize -Lines: 1 -4096 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/kernel/random/urandom_min_reseed_secs -Lines: 1 -60 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/kernel/random/write_wakeup_threshold -Lines: 1 -3072 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/proc/sys/vm -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/admin_reserve_kbytes -Lines: 1 -8192 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/block_dump -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/compact_unevictable_allowed -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirty_background_bytes -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirty_background_ratio -Lines: 1 -10 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirty_bytes -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirty_expire_centisecs -Lines: 1 -3000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirty_ratio -Lines: 1 -20 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirty_writeback_centisecs -Lines: 1 -500 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/dirtytime_expire_seconds -Lines: 1 -43200 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/drop_caches -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/extfrag_threshold -Lines: 1 -500 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/hugetlb_shm_group -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/laptop_mode -Lines: 1 -5 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/legacy_va_layout -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/lowmem_reserve_ratio -Lines: 1 -256 256 32 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/max_map_count -Lines: 1 -65530 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/memory_failure_early_kill -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/memory_failure_recovery -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/min_free_kbytes -Lines: 1 -67584 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/min_slab_ratio -Lines: 1 -5 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/min_unmapped_ratio -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/mmap_min_addr -Lines: 1 -65536 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/nr_hugepages -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/nr_hugepages_mempolicy -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/nr_overcommit_hugepages -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/numa_stat -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/numa_zonelist_order -Lines: 1 -Node -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/oom_dump_tasks -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/oom_kill_allocating_task -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/overcommit_kbytes -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/overcommit_memory -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/overcommit_ratio -Lines: 1 -50 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/page-cluster -Lines: 1 -3 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/panic_on_oom -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/percpu_pagelist_fraction -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/stat_interval -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/swappiness -Lines: 1 -60 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/user_reserve_kbytes -Lines: 1 -131072 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/vfs_cache_pressure -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/watermark_boost_factor -Lines: 1 -15000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/watermark_scale_factor -Lines: 1 -10 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/sys/vm/zone_reclaim_mode -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/proc/zoneinfo -Lines: 262 -Node 0, zone DMA - per-node stats - nr_inactive_anon 230981 - nr_active_anon 547580 - nr_inactive_file 316904 - nr_active_file 346282 - nr_unevictable 115467 - nr_slab_reclaimable 131220 - nr_slab_unreclaimable 47320 - nr_isolated_anon 0 - nr_isolated_file 0 - workingset_nodes 11627 - workingset_refault 466886 - workingset_activate 276925 - workingset_restore 84055 - workingset_nodereclaim 487 - nr_anon_pages 795576 - nr_mapped 215483 - nr_file_pages 761874 - nr_dirty 908 - nr_writeback 0 - nr_writeback_temp 0 - nr_shmem 224925 - nr_shmem_hugepages 0 - nr_shmem_pmdmapped 0 - nr_anon_transparent_hugepages 0 - nr_unstable 0 - nr_vmscan_write 12950 - nr_vmscan_immediate_reclaim 3033 - nr_dirtied 8007423 - nr_written 7752121 - nr_kernel_misc_reclaimable 0 - pages free 3952 - min 33 - low 41 - high 49 - spanned 4095 - present 3975 - managed 3956 - protection: (0, 2877, 7826, 7826, 7826) - nr_free_pages 3952 - nr_zone_inactive_anon 0 - nr_zone_active_anon 0 - nr_zone_inactive_file 0 - nr_zone_active_file 0 - nr_zone_unevictable 0 - nr_zone_write_pending 0 - nr_mlock 0 - nr_page_table_pages 0 - nr_kernel_stack 0 - nr_bounce 0 - nr_zspages 0 - nr_free_cma 0 - numa_hit 1 - numa_miss 0 - numa_foreign 0 - numa_interleave 0 - numa_local 1 - numa_other 0 - pagesets - cpu: 0 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 1 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 2 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 3 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 4 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 5 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 6 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - cpu: 7 - count: 0 - high: 0 - batch: 1 - vm stats threshold: 8 - node_unreclaimable: 0 - start_pfn: 1 -Node 0, zone DMA32 - pages free 204252 - min 19510 - low 21059 - high 22608 - spanned 1044480 - present 759231 - managed 742806 - protection: (0, 0, 4949, 4949, 4949) - nr_free_pages 204252 - nr_zone_inactive_anon 118558 - nr_zone_active_anon 106598 - nr_zone_inactive_file 75475 - nr_zone_active_file 70293 - nr_zone_unevictable 66195 - nr_zone_write_pending 64 - nr_mlock 4 - nr_page_table_pages 1756 - nr_kernel_stack 2208 - nr_bounce 0 - nr_zspages 0 - nr_free_cma 0 - numa_hit 113952967 - numa_miss 0 - numa_foreign 0 - numa_interleave 0 - numa_local 113952967 - numa_other 0 - pagesets - cpu: 0 - count: 345 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 1 - count: 356 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 2 - count: 325 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 3 - count: 346 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 4 - count: 321 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 5 - count: 316 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 6 - count: 373 - high: 378 - batch: 63 - vm stats threshold: 48 - cpu: 7 - count: 339 - high: 378 - batch: 63 - vm stats threshold: 48 - node_unreclaimable: 0 - start_pfn: 4096 -Node 0, zone Normal - pages free 18553 - min 11176 - low 13842 - high 16508 - spanned 1308160 - present 1308160 - managed 1268711 - protection: (0, 0, 0, 0, 0) - nr_free_pages 18553 - nr_zone_inactive_anon 112423 - nr_zone_active_anon 440982 - nr_zone_inactive_file 241429 - nr_zone_active_file 275989 - nr_zone_unevictable 49272 - nr_zone_write_pending 844 - nr_mlock 154 - nr_page_table_pages 9750 - nr_kernel_stack 15136 - nr_bounce 0 - nr_zspages 0 - nr_free_cma 0 - numa_hit 162718019 - numa_miss 0 - numa_foreign 0 - numa_interleave 26812 - numa_local 162718019 - numa_other 0 - pagesets - cpu: 0 - count: 316 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 1 - count: 366 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 2 - count: 60 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 3 - count: 256 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 4 - count: 253 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 5 - count: 159 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 6 - count: 311 - high: 378 - batch: 63 - vm stats threshold: 56 - cpu: 7 - count: 264 - high: 378 - batch: 63 - vm stats threshold: 56 - node_unreclaimable: 0 - start_pfn: 1048576 -Node 0, zone Movable - pages free 0 - min 0 - low 0 - high 0 - spanned 0 - present 0 - managed 0 - protection: (0, 0, 0, 0, 0) -Node 0, zone Device - pages free 0 - min 0 - low 0 - high 0 - spanned 0 - present 0 - managed 0 - protection: (0, 0, 0, 0, 0) -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/block -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/block/dm-0 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/dm-0/stat -Lines: 1 -6447303 0 710266738 1529043 953216 0 31201176 4557464 0 796160 6088971 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/block/sda -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/block/sda/queue -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/add_random -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/chunk_sectors -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/dax -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/discard_granularity -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/discard_max_bytes -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/discard_max_hw_bytes -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/discard_zeroes_data -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/fua -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/hw_sector_size -Lines: 1 -512 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/io_poll -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/io_poll_delay -Lines: 1 --1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/io_timeout -Lines: 1 -30000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/block/sda/queue/iosched -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/back_seek_max -Lines: 1 -16384 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/back_seek_penalty -Lines: 1 -2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/fifo_expire_async -Lines: 1 -250 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/fifo_expire_sync -Lines: 1 -125 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/low_latency -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/max_budget -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/slice_idle -Lines: 1 -8 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/slice_idle_us -Lines: 1 -8000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/strict_guarantees -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iosched/timeout_sync -Lines: 1 -125 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/iostats -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/logical_block_size -Lines: 1 -512 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/max_discard_segments -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/max_hw_sectors_kb -Lines: 1 -32767 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/max_integrity_segments -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/max_sectors_kb -Lines: 1 -1280 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/max_segment_size -Lines: 1 -65536 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/max_segments -Lines: 1 -168 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/minimum_io_size -Lines: 1 -512 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/nomerges -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/nr_requests -Lines: 1 -64 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/nr_zones -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/optimal_io_size -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/physical_block_size -Lines: 1 -512 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/read_ahead_kb -Lines: 1 -128 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/rotational -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/rq_affinity -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/scheduler -Lines: 1 -mq-deadline kyber [bfq] none -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/wbt_lat_usec -Lines: 1 -75000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/write_cache -Lines: 1 -write back -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/write_same_max_bytes -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/write_zeroes_max_bytes -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/queue/zoned -Lines: 1 -none -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/block/sda/stat -Lines: 1 -9652963 396792 759304206 412943 8422549 6731723 286915323 13947418 0 5658367 19174573 1 2 3 12 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/drm -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/drm/card0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/drm/card0/device -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/aer_dev_correctable -Lines: 9 -RxErr 0 -BadTLP 0 -BadDLLP 0 -Rollover 0 -Timeout 0 -NonFatalErr 0 -CorrIntErr 0 -HeaderOF 0 -TOTAL_ERR_COR 0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/aer_dev_fatal -Lines: 19 -Undefined 0 -DLP 0 -SDES 0 -TLP 0 -FCP 0 -CmpltTO 0 -CmpltAbrt 0 -UnxCmplt 0 -RxOF 0 -MalfTLP 0 -ECRC 0 -UnsupReq 0 -ACSViol 0 -UncorrIntErr 0 -BlockedTLP 0 -AtomicOpBlocked 0 -TLPBlockedErr 0 -PoisonTLPBlocked 0 -TOTAL_ERR_FATAL 0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/aer_dev_nonfatal -Lines: 19 -Undefined 0 -DLP 0 -SDES 0 -TLP 0 -FCP 0 -CmpltTO 0 -CmpltAbrt 0 -UnxCmplt 0 -RxOF 0 -MalfTLP 0 -ECRC 0 -UnsupReq 0 -ACSViol 0 -UncorrIntErr 0 -BlockedTLP 0 -AtomicOpBlocked 0 -TLPBlockedErr 0 -PoisonTLPBlocked 0 -TOTAL_ERR_NONFATAL 0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/ari_enabled -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/boot_vga -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/broken_parity_status -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/class -Lines: 1 -0x030000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/consistent_dma_mask_bits -Lines: 1 -44 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/current_link_speed -Lines: 1 -8.0 GT/s PCIe -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/current_link_width -Lines: 1 -16 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/d3cold_allowed -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/device -Lines: 1 -0x687f -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/dma_mask_bits -Lines: 1 -44 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/driver_override -Lines: 1 -(null) -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/gpu_busy_percent -Lines: 1 -4 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/irq -Lines: 1 -95 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/local_cpulist -Lines: 1 -0-15 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/local_cpus -Lines: 1 -0000ffff -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/max_link_speed -Lines: 1 -8.0 GT/s PCIe -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/max_link_width -Lines: 1 -16 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_gtt_total -Lines: 1 -8573157376 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_gtt_used -Lines: 1 -144560128 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_vis_vram_total -Lines: 1 -8573157376 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_vis_vram_used -Lines: 1 -1490378752 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_vram_total -Lines: 1 -8573157376 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_vram_used -Lines: 1 -1490378752 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/mem_info_vram_vendor -Lines: 1 -samsung -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/modalias -Lines: 1 -pci:v00001002d0000687Fsv00001043sd000004C4bc03sc00i00 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/msi_bus -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/numa_node -Lines: 1 --1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pcie_bw -Lines: 1 -6641 815 256 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pcie_replay_count -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/power_dpm_force_performance_level -Lines: 1 -manual -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/power_dpm_state -Lines: 1 -performance -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/power_state -Lines: 1 -D0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_cur_state -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_dpm_dcefclk -Lines: 5 -0: 600Mhz * -1: 720Mhz -2: 800Mhz -3: 847Mhz -4: 900Mhz -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_dpm_mclk -Lines: 4 -0: 167Mhz * -1: 500Mhz -2: 800Mhz -3: 945Mhz -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_dpm_pcie -Lines: 2 -0: 8.0GT/s, x16 -1: 8.0GT/s, x16 * -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_dpm_sclk -Lines: 8 -0: 852Mhz * -1: 991Mhz -2: 1084Mhz -3: 1138Mhz -4: 1200Mhz -5: 1401Mhz -6: 1536Mhz -7: 1630Mhz -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_dpm_socclk -Lines: 8 -0: 600Mhz -1: 720Mhz * -2: 800Mhz -3: 847Mhz -4: 900Mhz -5: 960Mhz -6: 1028Mhz -7: 1107Mhz -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_features -Lines: 32 -Current ppfeatures: 0x0000000019a1ff4f -FEATURES BITMASK ENABLEMENT -DPM_PREFETCHER 0x0000000000000001 Y -GFXCLK_DPM 0x0000000000000002 Y -UCLK_DPM 0x0000000000000004 Y -SOCCLK_DPM 0x0000000000000008 Y -UVD_DPM 0x0000000000000010 N -VCE_DPM 0x0000000000000020 N -ULV 0x0000000000000040 Y -MP0CLK_DPM 0x0000000000000080 N -LINK_DPM 0x0000000000000100 Y -DCEFCLK_DPM 0x0000000000000200 Y -AVFS 0x0000000000000400 Y -GFXCLK_DS 0x0000000000000800 Y -SOCCLK_DS 0x0000000000001000 Y -LCLK_DS 0x0000000000002000 Y -PPT 0x0000000000004000 Y -TDC 0x0000000000008000 Y -THERMAL 0x0000000000010000 Y -GFX_PER_CU_CG 0x0000000000020000 N -RM 0x0000000000040000 N -DCEFCLK_DS 0x0000000000080000 N -ACDC 0x0000000000100000 N -VR0HOT 0x0000000000200000 Y -VR1HOT 0x0000000000400000 N -FW_CTF 0x0000000000800000 Y -LED_DISPLAY 0x0000000001000000 Y -FAN_CONTROL 0x0000000002000000 N -FAST_PPT 0x0000000004000000 N -DIDT 0x0000000008000000 Y -ACG 0x0000000010000000 Y -PCC_LIMIT 0x0000000020000000 N -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_force_state -Lines: 1 - -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_mclk_od -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_num_states -Lines: 3 -states: 2 -0 boot -1 performance -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_od_clk_voltage -Lines: 18 -OD_SCLK: -0: 852Mhz 800mV -1: 991Mhz 900mV -2: 1084Mhz 950mV -3: 1138Mhz 1000mV -4: 1200Mhz 1050mV -5: 1401Mhz 1100mV -6: 1536Mhz 1150mV -7: 1630Mhz 1200mV -OD_MCLK: -0: 167Mhz 800mV -1: 500Mhz 800mV -2: 800Mhz 950mV -3: 945Mhz 1100mV -OD_RANGE: -SCLK: 852MHz 2400MHz -MCLK: 167MHz 1500MHz -VDDC: 800mV 1200mV -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_power_profile_mode -Lines: 8 -NUM MODE_NAME BUSY_SET_POINT FPS USE_RLC_BUSY MIN_ACTIVE_LEVEL - 0 BOOTUP_DEFAULT : 70 60 0 0 - 1 3D_FULL_SCREEN*: 70 60 1 3 - 2 POWER_SAVING : 90 60 0 0 - 3 VIDEO : 70 60 0 0 - 4 VR : 70 90 0 0 - 5 COMPUTE : 30 60 0 6 - 6 CUSTOM : 0 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/pp_sclk_od -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/product_name -Lines: 1 - -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/product_number -Lines: 1 - -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/resource -Lines: 13 -0x0000007c00000000 0x0000007dffffffff 0x000000000014220c -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000007e00000000 0x0000007e0fffffff 0x000000000014220c -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x000000000000d000 0x000000000000d0ff 0x0000000000040101 -0x00000000fcd00000 0x00000000fcd7ffff 0x0000000000040200 -0x00000000fcd80000 0x00000000fcd9ffff 0x0000000000046200 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/revision -Lines: 1 -0xc1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/serial_number -Lines: 1 - -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/subsystem_device -Lines: 1 -0x04c4 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/subsystem_vendor -Lines: 1 -0x1043 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/thermal_throttling_logging -Lines: 1 -0000:09:00.0: thermal throttling logging enabled, with interval 60 seconds -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/uevent -Lines: 6 -DRIVER=amdgpu -PCI_CLASS=30000 -PCI_ID=1002:687F -PCI_SUBSYS_ID=1043:04C4 -PCI_SLOT_NAME=0000:09:00.0 -MODALIAS=pci:v00001002d0000687Fsv00001043sd000004C4bc03sc00i00 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/unique_id -Lines: 1 -0123456789abcdef -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/vbios_version -Lines: 1 -115-D050PIL-100 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/drm/card0/device/vendor -Lines: 1 -0x1002 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/fc_host -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/fc_host/host0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/dev_loss_tmo -Lines: 1 -30 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/fabric_name -Lines: 1 -0x0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/node_name -Lines: 1 -0x2000e0071bce95f2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/port_id -Lines: 1 -0x000002 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/port_name -Lines: 1 -0x1000e0071bce95f2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/port_state -Lines: 1 -Online -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/port_type -Lines: 1 -Point-To-Point (direct nport connection) -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/speed -Lines: 1 -16 Gbit -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/fc_host/host0/statistics -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/dumped_frames -Lines: 1 -0xffffffffffffffff -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/error_frames -Lines: 1 -0x0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/fcp_packet_aborts -Lines: 1 -0x13 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/invalid_crc_count -Lines: 1 -0x2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/invalid_tx_word_count -Lines: 1 -0x8 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/link_failure_count -Lines: 1 -0x9 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/loss_of_signal_count -Lines: 1 -0x11 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/loss_of_sync_count -Lines: 1 -0x10 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/nos_count -Lines: 1 -0x12 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/rx_frames -Lines: 1 -0x3 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/rx_words -Lines: 1 -0x4 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/seconds_since_last_reset -Lines: 1 -0x7 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/tx_frames -Lines: 1 -0x5 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/statistics/tx_words -Lines: 1 -0x6 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/supported_classes -Lines: 1 -Class 3 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/supported_speeds -Lines: 1 -4 Gbit, 8 Gbit, 16 Gbit -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/fc_host/host0/symbolic_name -Lines: 1 -Emulex SN1100E2P FV12.4.270.3 DV12.4.0.0. HN:gotest. OS:Linux -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/hfi1_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/board_id -Lines: 1 -HPE 100Gb 1-port OP101 QSFP28 x16 PCIe Gen3 with Intel Omni-Path Adapter -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/fw_ver -Lines: 1 -1.27.0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/hfi1_0/ports -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/hfi1_0/ports/1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/VL15_dropped -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/excessive_buffer_overrun_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/link_downed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/link_error_recovery -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/local_link_integrity_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_constraint_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_data -Lines: 1 -345091702026 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_packets -Lines: 1 -638036947 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_remote_physical_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_rcv_switch_relay_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_constraint_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_data -Lines: 1 -273558326543 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_discards -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_packets -Lines: 1 -568318856 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/port_xmit_wait -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/counters/symbol_error -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/phys_state -Lines: 1 -5: LinkUp -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/rate -Lines: 1 -100 Gb/sec (4X EDR) -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/hfi1_0/ports/1/state -Lines: 1 -4: ACTIVE -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/mlx4_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/board_id -Lines: 1 -SM_1141000001000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/fw_ver -Lines: 1 -2.31.5050 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/hca_type -Lines: 1 -MT4099 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/mlx4_0/ports -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/VL15_dropped -Lines: 1 -0 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/excessive_buffer_overrun_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/link_downed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/link_error_recovery -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/local_link_integrity_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_constraint_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_data -Lines: 1 -2221223609 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_packets -Lines: 1 -87169372 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_remote_physical_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_rcv_switch_relay_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_constraint_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_data -Lines: 1 -26509113295 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_discards -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_packets -Lines: 1 -85734114 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/port_xmit_wait -Lines: 1 -3599 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/symbol_error -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/phys_state -Lines: 1 -5: LinkUp -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/rate -Lines: 1 -40 Gb/sec (4X QDR) -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/state -Lines: 1 -4: ACTIVE -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/VL15_dropped -Lines: 1 -0 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/excessive_buffer_overrun_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/link_downed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/link_error_recovery -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/local_link_integrity_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_constraint_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_data -Lines: 1 -2460436784 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_packets -Lines: 1 -89332064 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_remote_physical_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_rcv_switch_relay_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_constraint_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_data -Lines: 1 -26540356890 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_discards -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_packets -Lines: 1 -88622850 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/port_xmit_wait -Lines: 1 -3846 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/symbol_error -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/phys_state -Lines: 1 -5: LinkUp -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/rate -Lines: 1 -40 Gb/sec (4X QDR) -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/state -Lines: 1 -4: ACTIVE -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/net -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/net/eth0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/addr_assign_type -Lines: 1 -3 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/addr_len -Lines: 1 -6 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/address -Lines: 1 -01:01:01:01:01:01 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/broadcast -Lines: 1 -ff:ff:ff:ff:ff:ff -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/carrier -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/carrier_changes -Lines: 1 -2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/carrier_down_count -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/carrier_up_count -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/dev_id -Lines: 1 -0x20 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/device -SymlinkTo: ../../../devices/pci0000:00/0000:00:1f.6/ -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/dormant -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/duplex -Lines: 1 -full -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/flags -Lines: 1 -0x1303 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/ifalias -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/ifindex -Lines: 1 -2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/iflink -Lines: 1 -2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/link_mode -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/mtu -Lines: 1 -1500 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/name_assign_type -Lines: 1 -2 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/netdev_group -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/operstate -Lines: 1 -up -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/phys_port_id -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/phys_port_name -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/phys_switch_id -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/speed -Lines: 1 -1000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/tx_queue_len -Lines: 1 -1000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/net/eth0/type -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/nvme -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/nvme/nvme0 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/nvme/nvme0/firmware_rev -Lines: 1 -1B2QEXP7 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/nvme/nvme0/model -Lines: 1 -Samsung SSD 970 PRO 512GB -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/nvme/nvme0/serial -Lines: 1 -S680HF8N190894I -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/nvme/nvme0/state -Lines: 1 -live -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/power_supply -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/power_supply/AC -SymlinkTo: ../../devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/power_supply/BAT0 -SymlinkTo: ../../devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/powercap -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/powercap/intel-rapl -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl/enabled -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl/uevent -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/powercap/intel-rapl:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_0_max_power_uw -Lines: 1 -95000000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_0_name -Lines: 1 -long_term -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw -Lines: 1 -4090000000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_0_time_window_us -Lines: 1 -999424 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_1_max_power_uw -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_1_name -Lines: 1 -short_term -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_1_power_limit_uw -Lines: 1 -4090000000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/constraint_1_time_window_us -Lines: 1 -2440 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/enabled -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/energy_uj -Lines: 1 -240422366267 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/max_energy_range_uj -Lines: 1 -262143328850 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/name -Lines: 1 -package-0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0/uevent -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/powercap/intel-rapl:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/constraint_0_max_power_uw -Lines: 0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/constraint_0_name -Lines: 1 -long_term -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/constraint_0_power_limit_uw -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/constraint_0_time_window_us -Lines: 1 -976 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/enabled -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/energy_uj -Lines: 1 -118821284256 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/max_energy_range_uj -Lines: 1 -262143328850 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/name -Lines: 1 -core -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:0:0/uevent -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/powercap/intel-rapl:a -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_max_power_uw -Lines: 1 -95000000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_name -Lines: 1 -long_term -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_power_limit_uw -Lines: 1 -4090000000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_0_time_window_us -Lines: 1 -999424 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_max_power_uw -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_name -Lines: 1 -short_term -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_power_limit_uw -Lines: 1 -4090000000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/constraint_1_time_window_us -Lines: 1 -2440 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/enabled -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/energy_uj -Lines: 1 -240422366267 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/max_energy_range_uj -Lines: 1 -262143328850 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/name -Lines: 1 -package-10 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/powercap/intel-rapl:a/uevent -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/scsi_tape -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/nst0 -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/nst0a -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/nst0l -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/nst0m -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/st0 -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/st0a -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/st0l -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/scsi_tape/st0m -SymlinkTo: ../../devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/thermal -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/thermal/cooling_device0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/cooling_device0/cur_state -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/cooling_device0/max_state -Lines: 1 -50 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/cooling_device0/type -Lines: 1 -Processor -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/thermal/cooling_device1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/cooling_device1/cur_state -Lines: 1 --1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/cooling_device1/max_state -Lines: 1 -27 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/cooling_device1/type -Lines: 1 -intel_powerclamp -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/thermal/thermal_zone0 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone0/policy -Lines: 1 -step_wise -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone0/temp -Lines: 1 -49925 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone0/type -Lines: 1 -bcm2835_thermal -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/class/thermal/thermal_zone1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone1/mode -Lines: 1 -enabled -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone1/passive -Lines: 1 -0 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone1/policy -Lines: 1 -step_wise -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone1/temp -Lines: 1 --44000 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/class/thermal/thermal_zone1/type -Lines: 1 -acpitz -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/device -SymlinkTo: ../../../ACPI0003:00 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/online -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/async -Lines: 1 -disabled -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/autosuspend_delay_ms -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/control -Lines: 1 -auto -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/runtime_active_kids -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/runtime_active_time -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/runtime_enabled -Lines: 1 -disabled -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/runtime_status -Lines: 1 -unsupported -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/runtime_suspended_time -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/runtime_usage -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup -Lines: 1 -enabled -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_abort_count -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_active -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_active_count -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_count -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_expire_count -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_last_time_ms -Lines: 1 -10598 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_max_time_ms -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_prevent_sleep_time_ms -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/power/wakeup_total_time_ms -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/subsystem -SymlinkTo: ../../../../../../../../../class/power_supply -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/type -Lines: 1 -Mains -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/ACPI0003:00/power_supply/AC/uevent -Lines: 2 -POWER_SUPPLY_NAME=AC -POWER_SUPPLY_ONLINE=0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/alarm -Lines: 1 -2369000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/capacity -Lines: 1 -98 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/capacity_level -Lines: 1 -Normal -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/charge_start_threshold -Lines: 1 -95 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/charge_stop_threshold -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/cycle_count -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/device -SymlinkTo: ../../../PNP0C0A:00 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/energy_full -Lines: 1 -50060000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/energy_full_design -Lines: 1 -47520000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/energy_now -Lines: 1 -49450000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/manufacturer -Lines: 1 -LGC -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/model_name -Lines: 1 -LNV-45N1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/async -Lines: 1 -disabled -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/autosuspend_delay_ms -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/control -Lines: 1 -auto -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/runtime_active_kids -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/runtime_active_time -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/runtime_enabled -Lines: 1 -disabled -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/runtime_status -Lines: 1 -unsupported -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/runtime_suspended_time -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power/runtime_usage -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/power_now -Lines: 1 -4830000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/present -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/serial_number -Lines: 1 -38109 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/status -Lines: 1 -Discharging -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/subsystem -SymlinkTo: ../../../../../../../../../class/power_supply -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/technology -Lines: 1 -Li-ion -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/type -Lines: 1 -Battery -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/uevent -Lines: 16 -POWER_SUPPLY_NAME=BAT0 -POWER_SUPPLY_STATUS=Discharging -POWER_SUPPLY_PRESENT=1 -POWER_SUPPLY_TECHNOLOGY=Li-ion -POWER_SUPPLY_CYCLE_COUNT=0 -POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000 -POWER_SUPPLY_VOLTAGE_NOW=11750000 -POWER_SUPPLY_POWER_NOW=5064000 -POWER_SUPPLY_ENERGY_FULL_DESIGN=47520000 -POWER_SUPPLY_ENERGY_FULL=47390000 -POWER_SUPPLY_ENERGY_NOW=40730000 -POWER_SUPPLY_CAPACITY=85 -POWER_SUPPLY_CAPACITY_LEVEL=Normal -POWER_SUPPLY_MODEL_NAME=LNV-45N1 -POWER_SUPPLY_MANUFACTURER=LGC -POWER_SUPPLY_SERIAL_NUMBER=38109 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/voltage_min_design -Lines: 1 -10800000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/voltage_now -Lines: 1 -12229000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0a/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0l/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/nst0m/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0a/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0l/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/in_flight -Lines: 1 -1EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/io_ns -Lines: 1 -9247011087720EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/other_cnt -Lines: 1 -1409EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/read_byte_cnt -Lines: 1 -979383912EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/read_cnt -Lines: 1 -3741EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/read_ns -Lines: 1 -33788355744EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/resid_cnt -Lines: 1 -19EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/write_byte_cnt -Lines: 1 -1496246784000EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/write_cnt -Lines: 1 -53772916EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/scsi_tape/st0m/stats/write_ns -Lines: 1 -5233597394395EOF -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/dirty_data -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_hit_ratio -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_hits -Lines: 1 -289 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_day/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_hit_ratio -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_five_minute/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_hit_ratio -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_hour/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_hit_ratio -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_hits -Lines: 1 -546 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdb/bcache/stats_total/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/io_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/metadata_written -Lines: 1 -512 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/priority_stats -Lines: 5 -Unused: 99% -Metadata: 0% -Average: 10473 -Sectors per Q: 64 -Quantiles: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946] -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:0d.0/ata5/host4/target4:0:0/4:0:0:0/block/sdc/bcache/written -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/pci0000:00/0000:00:1f.6 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/ari_enabled -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/broken_parity_status -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/class -Lines: 1 -0x020000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/consistent_dma_mask_bits -Lines: 1 -64 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/d3cold_allowed -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/device -Lines: 1 -0x15d7 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/dma_mask_bits -Lines: 1 -64 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/driver_override -Lines: 1 -(null) -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/irq -Lines: 1 -140 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/local_cpulist -Lines: 1 -0-7 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/local_cpus -Lines: 1 -ff -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/modalias -Lines: 1 -pci:v00008086d000015D7sv000017AAsd0000225Abc02sc00i00 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/msi_bus -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/numa_node -Lines: 1 --1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/resource -Lines: 13 -0x00000000ec200000 0x00000000ec21ffff 0x0000000000040200 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -0x0000000000000000 0x0000000000000000 0x0000000000000000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/revision -Lines: 1 -0x21 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/subsystem_device -Lines: 1 -0x225a -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/subsystem_vendor -Lines: 1 -0x17aa -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/uevent -Lines: 6 -DRIVER=e1000e -PCI_CLASS=20000 -PCI_ID=8086:15D7 -PCI_SUBSYS_ID=17AA:225A -PCI_SLOT_NAME=0000:00:1f.6 -MODALIAS=pci:v00008086d000015D7sv000017AAsd0000225Abc02sc00i00 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/pci0000:00/0000:00:1f.6/vendor -Lines: 1 -0x8086 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/rbd -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/rbd/0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/rbd/0/name -Lines: 1 -demo -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/rbd/0/pool -Lines: 1 -iscsi-images -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/rbd/1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/rbd/1/name -Lines: 1 -wrong -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/rbd/1/pool -Lines: 1 -wrong-images -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/clocksource -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/clocksource/clocksource0 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/clocksource/clocksource0/available_clocksource -Lines: 1 -tsc hpet acpi_pm -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/clocksource/clocksource0/current_clocksource -Lines: 1 -tsc -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu0 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/cpufreq -SymlinkTo: ../cpufreq/policy0 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu0/thermal_throttle -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/thermal_throttle/core_throttle_count -Lines: 1 -10084 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/thermal_throttle/package_throttle_count -Lines: 1 -34818 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu0/topology -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/topology/core_id -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/topology/core_siblings -Lines: 1 -ff -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/topology/core_siblings_list -Lines: 1 -0-7 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/topology/physical_package_id -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/topology/thread_siblings -Lines: 1 -11 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu0/topology/thread_siblings_list -Lines: 1 -0,4 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu1 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu1/cpufreq -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq -Lines: 1 -1200195 -Mode: 400 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq -Lines: 1 -3300000 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_min_freq -Lines: 1 -1200000 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_transition_latency -Lines: 1 -4294967295 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/related_cpus -Lines: 1 -1 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_available_governors -Lines: 1 -performance powersave -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_driver -Lines: 1 -intel_pstate -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_governor -Lines: 1 -powersave -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq -Lines: 1 -3300000 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq -Lines: 1 -1200000 -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed -Lines: 1 - -Mode: 664 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu1/thermal_throttle -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/thermal_throttle/core_throttle_count -Lines: 1 -523 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/thermal_throttle/package_throttle_count -Lines: 1 -34818 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpu1/topology -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/topology/core_id -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/topology/core_siblings -Lines: 1 -ff -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/topology/core_siblings_list -Lines: 1 -0-7 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/topology/physical_package_id -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/topology/thread_siblings -Lines: 1 -22 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpu1/topology/thread_siblings_list -Lines: 1 -1,5 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpufreq -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpufreq/policy0 -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/affected_cpus -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq -Lines: 1 -2400000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq -Lines: 1 -800000 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_transition_latency -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/related_cpus -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_available_governors -Lines: 1 -performance powersave -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq -Lines: 1 -1219917 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_driver -Lines: 1 -intel_pstate -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_governor -Lines: 1 -powersave -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq -Lines: 1 -2400000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq -Lines: 1 -800000 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed -Lines: 1 - -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/node -Mode: 775 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/node/node1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/node/node1/vmstat -Lines: 6 -nr_free_pages 1 -nr_zone_inactive_anon 2 -nr_zone_active_anon 3 -nr_zone_inactive_file 4 -nr_zone_active_file 5 -nr_zone_unevictable 6 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/devices/system/node/node2 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/devices/system/node/node2/vmstat -Lines: 6 -nr_free_pages 7 -nr_zone_inactive_anon 8 -nr_zone_active_anon 9 -nr_zone_inactive_file 10 -nr_zone_active_file 11 -nr_zone_unevictable 12 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/average_key_size -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0 -Mode: 777 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/dirty_data -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_hit_ratio -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_hits -Lines: 1 -289 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_day/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_hit_ratio -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_five_minute/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_hit_ratio -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_hour/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_hit_ratio -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_hits -Lines: 1 -546 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/stats_total/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/bdev0/writeback_rate_debug -Lines: 7 -rate: 1.1M/sec -dirty: 20.4G -target: 20.4G -proportional: 427.5k -integral: 790.0k -change: 321.5k/sec -next io: 17ms -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/btree_cache_size -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0 -Mode: 777 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/io_errors -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/metadata_written -Lines: 1 -512 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/priority_stats -Lines: 5 -Unused: 99% -Metadata: 0% -Average: 10473 -Sectors per Q: 64 -Quantiles: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946 20946] -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache0/written -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/cache_available_percent -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/congested -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/active_journal_entries -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/btree_nodes -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/btree_read_average_duration_us -Lines: 1 -1305 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/internal/cache_read_races -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/root_usage_percent -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_hit_ratio -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_hits -Lines: 1 -289 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_day/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_hit_ratio -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_five_minute/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_hit_ratio -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_hour/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/bypassed -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_bypass_hits -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_bypass_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_hit_ratio -Lines: 1 -100 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_hits -Lines: 1 -546 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_miss_collisions -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_misses -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/stats_total/cache_readaheads -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/bcache/deaddd54-c735-46d5-868e-f331c5fd7c74/tree_depth -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/bytes_may_use -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/bytes_readonly -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/bytes_reserved -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/bytes_used -Lines: 1 -808189952 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/disk_total -Lines: 1 -2147483648 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/disk_used -Lines: 1 -808189952 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/flags -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/raid0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/raid0/total_bytes -Lines: 1 -2147483648 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/raid0/used_bytes -Lines: 1 -808189952 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/total_bytes -Lines: 1 -2147483648 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/data/total_bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/global_rsv_reserved -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/global_rsv_size -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/bytes_may_use -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/bytes_readonly -Lines: 1 -131072 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/bytes_reserved -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/bytes_used -Lines: 1 -933888 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/disk_total -Lines: 1 -2147483648 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/disk_used -Lines: 1 -1867776 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/flags -Lines: 1 -4 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/raid1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/raid1/total_bytes -Lines: 1 -1073741824 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/raid1/used_bytes -Lines: 1 -933888 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/total_bytes -Lines: 1 -1073741824 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/metadata/total_bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/bytes_may_use -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/bytes_readonly -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/bytes_reserved -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/bytes_used -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/disk_total -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/disk_used -Lines: 1 -32768 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/flags -Lines: 1 -2 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/raid1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/raid1/total_bytes -Lines: 1 -8388608 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/raid1/used_bytes -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/total_bytes -Lines: 1 -8388608 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/allocation/system/total_bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/clone_alignment -Lines: 1 -4096 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/devices -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/devices/loop25 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/devices/loop25/size -Lines: 1 -20971520 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/devices/loop26 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/devices/loop26/size -Lines: 1 -20971520 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/features -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/features/big_metadata -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/features/extended_iref -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/features/mixed_backref -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/features/skinny_metadata -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/label -Lines: 1 -fixture -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/metadata_uuid -Lines: 1 -0abb23a9-579b-43e6-ad30-227ef47fcb9d -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/nodesize -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/quota_override -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/0abb23a9-579b-43e6-ad30-227ef47fcb9d/sectorsize -Lines: 1 -4096 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/bytes_may_use -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/bytes_readonly -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/bytes_reserved -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/bytes_used -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/disk_total -Lines: 1 -644087808 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/disk_used -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/flags -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/raid5 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/raid5/total_bytes -Lines: 1 -644087808 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/raid5/used_bytes -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/total_bytes -Lines: 1 -644087808 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/data/total_bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/global_rsv_reserved -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/global_rsv_size -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/bytes_may_use -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/bytes_readonly -Lines: 1 -262144 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/bytes_reserved -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/bytes_used -Lines: 1 -114688 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/disk_total -Lines: 1 -429391872 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/disk_used -Lines: 1 -114688 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/flags -Lines: 1 -4 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/raid6 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/raid6/total_bytes -Lines: 1 -429391872 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/raid6/used_bytes -Lines: 1 -114688 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/total_bytes -Lines: 1 -429391872 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/metadata/total_bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/bytes_may_use -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/bytes_readonly -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/bytes_reserved -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/bytes_used -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/disk_total -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/disk_used -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/flags -Lines: 1 -2 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/raid6 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/raid6/total_bytes -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/raid6/used_bytes -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/total_bytes -Lines: 1 -16777216 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/allocation/system/total_bytes_pinned -Lines: 1 -0 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/clone_alignment -Lines: 1 -4096 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/devices -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/devices/loop22 -SymlinkTo: ../../../../devices/virtual/block/loop22 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/devices/loop23 -SymlinkTo: ../../../../devices/virtual/block/loop23 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/devices/loop24 -SymlinkTo: ../../../../devices/virtual/block/loop24 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/devices/loop25 -SymlinkTo: ../../../../devices/virtual/block/loop25 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/features -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/features/big_metadata -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/features/extended_iref -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/features/mixed_backref -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/features/raid56 -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/features/skinny_metadata -Lines: 1 -1 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/label -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/metadata_uuid -Lines: 1 -7f07c59f-6136-449c-ab87-e1cf2328731b -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/nodesize -Lines: 1 -16384 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/quota_override -Lines: 1 -0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/btrfs/7f07c59f-6136-449c-ab87-e1cf2328731b/sectorsize -Lines: 1 -4096 -Mode: 444 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/xfs -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/xfs/sda1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/xfs/sda1/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/xfs/sda1/stats/stats -Lines: 1 -extent_alloc 1 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/xfs/sdb1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/fs/xfs/sdb1/stats -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/fs/xfs/sdb1/stats/stats -Lines: 1 -extent_alloc 2 0 0 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/fileio_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/fileio_1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/fileio_1/file_lio_1G -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/fileio_1/file_lio_1G/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/fileio_1/file_lio_1G/udev_path -Lines: 1 -/home/iscsi/file_back_1G -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/iblock_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/iblock_0/block_lio_rbd1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/iblock_0/block_lio_rbd1/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/iblock_0/block_lio_rbd1/udev_path -Lines: 1 -/dev/rbd1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/rbd_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/rbd_0/iscsi-images-demo -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/rbd_0/iscsi-images-demo/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/rbd_0/iscsi-images-demo/udev_path -Lines: 1 -/dev/rbd/iscsi-images/demo -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/rd_mcp_119 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/core/rd_mcp_119/ramdisk_lio_1G -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/rd_mcp_119/ramdisk_lio_1G/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/core/rd_mcp_119/ramdisk_lio_1G/udev_path -Lines: 0 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/7f4a4eb56d -SymlinkTo: ../../../../../../target/core/rd_mcp_119/ramdisk_lio_1G -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds -Lines: 1 -204950 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes -Lines: 1 -10325 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.8888bbbbddd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes -Lines: 1 -40325 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/795b7c7026 -SymlinkTo: ../../../../../../target/core/iblock_0/block_lio_rbd1 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds -Lines: 1 -104950 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes -Lines: 1 -20095 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2003-01.org.linux-iscsi.osd1.x8664:sn.abcd1abcd2ab/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes -Lines: 1 -71235 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/fff5e16686 -SymlinkTo: ../../../../../../target/core/fileio_1/file_lio_1G -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds -Lines: 1 -301950 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes -Lines: 1 -10195 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:dev.rbd0/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes -Lines: 1 -30195 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/enable -Lines: 1 -1 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0 -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/eba1edf893 -SymlinkTo: ../../../../../../target/core/rbd_0/iscsi-images-demo -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Directory: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port -Mode: 755 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/in_cmds -Lines: 1 -1234 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/read_mbytes -Lines: 1 -1504 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Path: fixtures/sys/kernel/config/target/iscsi/iqn.2016-11.org.linux-iscsi.igw.x86:sn.ramdemo/tpgt_1/lun/lun_0/statistics/scsi_tgt_port/write_mbytes -Lines: 1 -4733 -Mode: 644 -# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/github.com/prometheus/procfs/internal/fs/fs.go b/vendor/github.com/prometheus/procfs/internal/fs/fs.go index 0040753b1..3c18c7610 100644 --- a/vendor/github.com/prometheus/procfs/internal/fs/fs.go +++ b/vendor/github.com/prometheus/procfs/internal/fs/fs.go @@ -26,7 +26,7 @@ const ( // DefaultSysMountPoint is the common mount point of the sys filesystem. DefaultSysMountPoint = "/sys" - // DefaultConfigfsMountPoint is the common mount point of the configfs + // DefaultConfigfsMountPoint is the common mount point of the configfs. DefaultConfigfsMountPoint = "/sys/kernel/config" ) diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go index 22cb07a6b..b030951fa 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/parse.go +++ b/vendor/github.com/prometheus/procfs/internal/util/parse.go @@ -14,7 +14,7 @@ package util import ( - "io/ioutil" + "os" "strconv" "strings" ) @@ -66,7 +66,7 @@ func ParsePInt64s(ss []string) ([]*int64, error) { // ReadUintFromFile reads a file and attempts to parse a uint64 from it. func ReadUintFromFile(path string) (uint64, error) { - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { return 0, err } @@ -75,7 +75,7 @@ func ReadUintFromFile(path string) (uint64, error) { // ReadIntFromFile reads a file and attempts to parse a int64 from it. func ReadIntFromFile(path string) (int64, error) { - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { return 0, err } diff --git a/vendor/github.com/prometheus/procfs/internal/util/readfile.go b/vendor/github.com/prometheus/procfs/internal/util/readfile.go index 8051161b2..71b7a70eb 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/readfile.go +++ b/vendor/github.com/prometheus/procfs/internal/util/readfile.go @@ -15,17 +15,16 @@ package util import ( "io" - "io/ioutil" "os" ) -// ReadFileNoStat uses ioutil.ReadAll to read contents of entire file. -// This is similar to ioutil.ReadFile but without the call to os.Stat, because +// ReadFileNoStat uses io.ReadAll to read contents of entire file. +// This is similar to os.ReadFile but without the call to os.Stat, because // many files in /proc and /sys report incorrect file sizes (either 0 or 4096). -// Reads a max file size of 512kB. For files larger than this, a scanner +// Reads a max file size of 1024kB. For files larger than this, a scanner // should be used. func ReadFileNoStat(filename string) ([]byte, error) { - const maxBufferSize = 1024 * 512 + const maxBufferSize = 1024 * 1024 f, err := os.Open(filename) if err != nil { @@ -34,5 +33,5 @@ func ReadFileNoStat(filename string) ([]byte, error) { defer f.Close() reader := io.LimitReader(f, maxBufferSize) - return ioutil.ReadAll(reader) + return io.ReadAll(reader) } diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go index c07de0b6c..1ab875cee 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go +++ b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile.go @@ -11,7 +11,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build linux,!appengine +//go:build (linux || darwin) && !appengine +// +build linux darwin +// +build !appengine package util @@ -21,7 +23,7 @@ import ( "syscall" ) -// SysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly. +// SysReadFile is a simplified os.ReadFile that invokes syscall.Read directly. // https://github.com/prometheus/node_exporter/pull/728/files // // Note that this function will not read files larger than 128 bytes. @@ -33,7 +35,7 @@ func SysReadFile(file string) (string, error) { defer f.Close() // On some machines, hwmon drivers are broken and return EAGAIN. This causes - // Go's ioutil.ReadFile implementation to poll forever. + // Go's os.ReadFile implementation to poll forever. // // Since we either want to read data or bail immediately, do the simplest // possible read using syscall directly. diff --git a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go index bd55b4537..1d86f5e63 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go +++ b/vendor/github.com/prometheus/procfs/internal/util/sysreadfile_compat.go @@ -11,7 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build linux,appengine !linux +//go:build (linux && appengine) || (!linux && !darwin) +// +build linux,appengine !linux,!darwin package util diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index 89e447746..391c07957 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -20,7 +20,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "os" "strconv" @@ -84,7 +83,7 @@ func parseIPVSStats(r io.Reader) (IPVSStats, error) { stats IPVSStats ) - statContent, err := ioutil.ReadAll(r) + statContent, err := io.ReadAll(r) if err != nil { return IPVSStats{}, err } diff --git a/vendor/github.com/prometheus/procfs/kernel_random.go b/vendor/github.com/prometheus/procfs/kernel_random.go index da3a941d6..db88566bd 100644 --- a/vendor/github.com/prometheus/procfs/kernel_random.go +++ b/vendor/github.com/prometheus/procfs/kernel_random.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !windows // +build !windows package procfs diff --git a/vendor/github.com/prometheus/procfs/loadavg.go b/vendor/github.com/prometheus/procfs/loadavg.go index 0cce190ec..0096cafbd 100644 --- a/vendor/github.com/prometheus/procfs/loadavg.go +++ b/vendor/github.com/prometheus/procfs/loadavg.go @@ -21,7 +21,7 @@ import ( "github.com/prometheus/procfs/internal/util" ) -// LoadAvg represents an entry in /proc/loadavg +// LoadAvg represents an entry in /proc/loadavg. type LoadAvg struct { Load1 float64 Load5 float64 diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go index f0b9e5f75..a95c889cb 100644 --- a/vendor/github.com/prometheus/procfs/mdstat.go +++ b/vendor/github.com/prometheus/procfs/mdstat.go @@ -15,7 +15,7 @@ package procfs import ( "fmt" - "io/ioutil" + "os" "regexp" "strconv" "strings" @@ -64,7 +64,7 @@ type MDStat struct { // structs containing the relevant info. More information available here: // https://raid.wiki.kernel.org/index.php/Mdstat func (fs FS) MDStat() ([]MDStat, error) { - data, err := ioutil.ReadFile(fs.proc.Path("mdstat")) + data, err := os.ReadFile(fs.proc.Path("mdstat")) if err != nil { return nil, err } @@ -166,8 +166,12 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { } func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) { + statusFields := strings.Fields(statusLine) + if len(statusFields) < 1 { + return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q", statusLine) + } - sizeStr := strings.Fields(statusLine)[0] + sizeStr := statusFields[0] size, err = strconv.ParseInt(sizeStr, 10, 64) if err != nil { return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err) diff --git a/vendor/github.com/prometheus/procfs/net_conntrackstat.go b/vendor/github.com/prometheus/procfs/net_conntrackstat.go index 9964a3600..8300daca0 100644 --- a/vendor/github.com/prometheus/procfs/net_conntrackstat.go +++ b/vendor/github.com/prometheus/procfs/net_conntrackstat.go @@ -25,7 +25,7 @@ import ( ) // A ConntrackStatEntry represents one line from net/stat/nf_conntrack -// and contains netfilter conntrack statistics at one CPU core +// and contains netfilter conntrack statistics at one CPU core. type ConntrackStatEntry struct { Entries uint64 Found uint64 @@ -38,12 +38,12 @@ type ConntrackStatEntry struct { SearchRestart uint64 } -// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores +// ConntrackStat retrieves netfilter's conntrack statistics, split by CPU cores. func (fs FS) ConntrackStat() ([]ConntrackStatEntry, error) { return readConntrackStat(fs.proc.Path("net", "stat", "nf_conntrack")) } -// Parses a slice of ConntrackStatEntries from the given filepath +// Parses a slice of ConntrackStatEntries from the given filepath. func readConntrackStat(path string) ([]ConntrackStatEntry, error) { // This file is small and can be read with one syscall. b, err := util.ReadFileNoStat(path) @@ -61,7 +61,7 @@ func readConntrackStat(path string) ([]ConntrackStatEntry, error) { return stat, nil } -// Reads the contents of a conntrack statistics file and parses a slice of ConntrackStatEntries +// Reads the contents of a conntrack statistics file and parses a slice of ConntrackStatEntries. func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) { var entries []ConntrackStatEntry @@ -79,7 +79,7 @@ func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) { return entries, nil } -// Parses a ConntrackStatEntry from given array of fields +// Parses a ConntrackStatEntry from given array of fields. func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) { if len(fields) != 17 { return nil, fmt.Errorf("invalid conntrackstat entry, missing fields") @@ -143,7 +143,7 @@ func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) { return entry, nil } -// Parses a uint64 from given hex in string +// Parses a uint64 from given hex in string. func parseConntrackStatField(field string) (uint64, error) { val, err := strconv.ParseUint(field, 16, 64) if err != nil { diff --git a/vendor/github.com/prometheus/procfs/net_dev.go b/vendor/github.com/prometheus/procfs/net_dev.go index 47a710bef..e66208aa0 100644 --- a/vendor/github.com/prometheus/procfs/net_dev.go +++ b/vendor/github.com/prometheus/procfs/net_dev.go @@ -87,17 +87,17 @@ func newNetDev(file string) (NetDev, error) { // parseLine parses a single line from the /proc/net/dev file. Header lines // must be filtered prior to calling this method. func (netDev NetDev) parseLine(rawLine string) (*NetDevLine, error) { - parts := strings.SplitN(rawLine, ":", 2) - if len(parts) != 2 { + idx := strings.LastIndex(rawLine, ":") + if idx == -1 { return nil, errors.New("invalid net/dev line, missing colon") } - fields := strings.Fields(strings.TrimSpace(parts[1])) + fields := strings.Fields(strings.TrimSpace(rawLine[idx+1:])) var err error line := &NetDevLine{} // Interface Name - line.Name = strings.TrimSpace(parts[0]) + line.Name = strings.TrimSpace(rawLine[:idx]) if line.Name == "" { return nil, errors.New("invalid net/dev line, empty interface name") } diff --git a/vendor/github.com/prometheus/procfs/net_ip_socket.go b/vendor/github.com/prometheus/procfs/net_ip_socket.go index 8c9ee3de8..7fd57d7f4 100644 --- a/vendor/github.com/prometheus/procfs/net_ip_socket.go +++ b/vendor/github.com/prometheus/procfs/net_ip_socket.go @@ -34,7 +34,7 @@ const ( readLimit = 4294967296 // Byte -> 4 GiB ) -// this contains generic data structures for both udp and tcp sockets +// This contains generic data structures for both udp and tcp sockets. type ( // NetIPSocket represents the contents of /proc/net/{t,u}dp{,6} file without the header. NetIPSocket []*netIPSocketLine diff --git a/vendor/github.com/prometheus/procfs/net_protocols.go b/vendor/github.com/prometheus/procfs/net_protocols.go index 8c6de3791..374b6f73f 100644 --- a/vendor/github.com/prometheus/procfs/net_protocols.go +++ b/vendor/github.com/prometheus/procfs/net_protocols.go @@ -23,7 +23,7 @@ import ( "github.com/prometheus/procfs/internal/util" ) -// NetProtocolStats stores the contents from /proc/net/protocols +// NetProtocolStats stores the contents from /proc/net/protocols. type NetProtocolStats map[string]NetProtocolStatLine // NetProtocolStatLine contains a single line parsed from /proc/net/protocols. We @@ -41,7 +41,7 @@ type NetProtocolStatLine struct { Capabilities NetProtocolCapabilities } -// NetProtocolCapabilities contains a list of capabilities for each protocol +// NetProtocolCapabilities contains a list of capabilities for each protocol. type NetProtocolCapabilities struct { Close bool // 8 Connect bool // 9 diff --git a/vendor/github.com/prometheus/procfs/net_softnet.go b/vendor/github.com/prometheus/procfs/net_softnet.go index 46f12c61d..a94f86dc4 100644 --- a/vendor/github.com/prometheus/procfs/net_softnet.go +++ b/vendor/github.com/prometheus/procfs/net_softnet.go @@ -30,13 +30,13 @@ import ( // * Linux 4.17 https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162 // and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810. -// SoftnetStat contains a single row of data from /proc/net/softnet_stat +// SoftnetStat contains a single row of data from /proc/net/softnet_stat. type SoftnetStat struct { - // Number of processed packets + // Number of processed packets. Processed uint32 - // Number of dropped packets + // Number of dropped packets. Dropped uint32 - // Number of times processing packets ran out of quota + // Number of times processing packets ran out of quota. TimeSqueezed uint32 } diff --git a/vendor/github.com/prometheus/procfs/xfrm.go b/vendor/github.com/prometheus/procfs/net_xfrm.go similarity index 96% rename from vendor/github.com/prometheus/procfs/xfrm.go rename to vendor/github.com/prometheus/procfs/net_xfrm.go index eed07c7d7..f9d9d243d 100644 --- a/vendor/github.com/prometheus/procfs/xfrm.go +++ b/vendor/github.com/prometheus/procfs/net_xfrm.go @@ -79,10 +79,13 @@ type XfrmStat struct { // Policy is dead XfrmOutPolDead int // Policy Error - XfrmOutPolError int - XfrmFwdHdrError int + XfrmOutPolError int + // Forward routing of a packet is not allowed + XfrmFwdHdrError int + // State is invalid, perhaps expired XfrmOutStateInvalid int - XfrmAcquireError int + // State hasn’t been fully acquired before use + XfrmAcquireError int } // NewXfrmStat reads the xfrm_stat statistics. diff --git a/vendor/github.com/prometheus/procfs/netstat.go b/vendor/github.com/prometheus/procfs/netstat.go index 94d892f11..dcea9c5a6 100644 --- a/vendor/github.com/prometheus/procfs/netstat.go +++ b/vendor/github.com/prometheus/procfs/netstat.go @@ -21,13 +21,13 @@ import ( "strings" ) -// NetStat contains statistics for all the counters from one file +// NetStat contains statistics for all the counters from one file. type NetStat struct { - Filename string Stats map[string][]uint64 + Filename string } -// NetStat retrieves stats from /proc/net/stat/ +// NetStat retrieves stats from `/proc/net/stat/`. func (fs FS) NetStat() ([]NetStat, error) { statFiles, err := filepath.Glob(fs.proc.Path("net/stat/*")) if err != nil { @@ -55,7 +55,7 @@ func (fs FS) NetStat() ([]NetStat, error) { // Other strings represent per-CPU counters for scanner.Scan() { for num, counter := range strings.Fields(scanner.Text()) { - value, err := strconv.ParseUint(counter, 16, 32) + value, err := strconv.ParseUint(counter, 16, 64) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go index 28f696803..c30223af7 100644 --- a/vendor/github.com/prometheus/procfs/proc.go +++ b/vendor/github.com/prometheus/procfs/proc.go @@ -16,7 +16,7 @@ package procfs import ( "bytes" "fmt" - "io/ioutil" + "io" "os" "strconv" "strings" @@ -82,7 +82,7 @@ func (fs FS) Self() (Proc, error) { // NewProc returns a process for the given pid. // -// Deprecated: use fs.Proc() instead +// Deprecated: Use fs.Proc() instead. func (fs FS) NewProc(pid int) (Proc, error) { return fs.Proc(pid) } @@ -142,7 +142,7 @@ func (p Proc) Wchan() (string, error) { } defer f.Close() - data, err := ioutil.ReadAll(f) + data, err := io.ReadAll(f) if err != nil { return "", err } @@ -185,7 +185,7 @@ func (p Proc) Cwd() (string, error) { return wd, err } -// RootDir returns the absolute path to the process's root directory (as set by chroot) +// RootDir returns the absolute path to the process's root directory (as set by chroot). func (p Proc) RootDir() (string, error) { rdir, err := os.Readlink(p.path("root")) if os.IsNotExist(err) { @@ -311,7 +311,7 @@ func (p Proc) FileDescriptorsInfo() (ProcFDInfos, error) { // Schedstat returns task scheduling information for the process. func (p Proc) Schedstat() (ProcSchedstat, error) { - contents, err := ioutil.ReadFile(p.path("schedstat")) + contents, err := os.ReadFile(p.path("schedstat")) if err != nil { return ProcSchedstat{}, err } diff --git a/vendor/github.com/prometheus/procfs/proc_cgroup.go b/vendor/github.com/prometheus/procfs/proc_cgroup.go index be45b7987..cca03327c 100644 --- a/vendor/github.com/prometheus/procfs/proc_cgroup.go +++ b/vendor/github.com/prometheus/procfs/proc_cgroup.go @@ -45,7 +45,7 @@ type Cgroup struct { } // parseCgroupString parses each line of the /proc/[pid]/cgroup file -// Line format is hierarchyID:[controller1,controller2]:path +// Line format is hierarchyID:[controller1,controller2]:path. func parseCgroupString(cgroupStr string) (*Cgroup, error) { var err error @@ -69,7 +69,7 @@ func parseCgroupString(cgroupStr string) (*Cgroup, error) { return cgroup, nil } -// parseCgroups reads each line of the /proc/[pid]/cgroup file +// parseCgroups reads each line of the /proc/[pid]/cgroup file. func parseCgroups(data []byte) ([]Cgroup, error) { var cgroups []Cgroup scanner := bufio.NewScanner(bytes.NewReader(data)) @@ -88,7 +88,7 @@ func parseCgroups(data []byte) ([]Cgroup, error) { // Cgroups reads from /proc//cgroups and returns a []*Cgroup struct locating this PID in each process // control hierarchy running on this system. On every system (v1 and v2), all hierarchies contain all processes, -// so the len of the returned struct is equal to the number of active hierarchies on this system +// so the len of the returned struct is equal to the number of active hierarchies on this system. func (p Proc) Cgroups() ([]Cgroup, error) { data, err := util.ReadFileNoStat(p.path("cgroup")) if err != nil { diff --git a/vendor/github.com/prometheus/procfs/proc_cgroups.go b/vendor/github.com/prometheus/procfs/proc_cgroups.go new file mode 100644 index 000000000..24d4dce9c --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_cgroups.go @@ -0,0 +1,98 @@ +// 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 procfs + +import ( + "bufio" + "bytes" + "fmt" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// CgroupSummary models one line from /proc/cgroups. +// This file contains information about the controllers that are compiled into the kernel. +// +// Also see http://man7.org/linux/man-pages/man7/cgroups.7.html +type CgroupSummary struct { + // The name of the controller. controller is also known as subsystem. + SubsysName string + // The unique ID of the cgroup hierarchy on which this controller is mounted. + Hierarchy int + // The number of control groups in this hierarchy using this controller. + Cgroups int + // This field contains the value 1 if this controller is enabled, or 0 if it has been disabled + Enabled int +} + +// parseCgroupSummary parses each line of the /proc/cgroup file +// Line format is `subsys_name hierarchy num_cgroups enabled`. +func parseCgroupSummaryString(CgroupSummaryStr string) (*CgroupSummary, error) { + var err error + + fields := strings.Fields(CgroupSummaryStr) + // require at least 4 fields + if len(fields) < 4 { + return nil, fmt.Errorf("at least 4 fields required, found %d fields in cgroup info string: %s", len(fields), CgroupSummaryStr) + } + + CgroupSummary := &CgroupSummary{ + SubsysName: fields[0], + } + CgroupSummary.Hierarchy, err = strconv.Atoi(fields[1]) + if err != nil { + return nil, fmt.Errorf("failed to parse hierarchy ID") + } + CgroupSummary.Cgroups, err = strconv.Atoi(fields[2]) + if err != nil { + return nil, fmt.Errorf("failed to parse Cgroup Num") + } + CgroupSummary.Enabled, err = strconv.Atoi(fields[3]) + if err != nil { + return nil, fmt.Errorf("failed to parse Enabled") + } + return CgroupSummary, nil +} + +// parseCgroupSummary reads each line of the /proc/cgroup file. +func parseCgroupSummary(data []byte) ([]CgroupSummary, error) { + var CgroupSummarys []CgroupSummary + scanner := bufio.NewScanner(bytes.NewReader(data)) + for scanner.Scan() { + CgroupSummaryString := scanner.Text() + // ignore comment lines + if strings.HasPrefix(CgroupSummaryString, "#") { + continue + } + CgroupSummary, err := parseCgroupSummaryString(CgroupSummaryString) + if err != nil { + return nil, err + } + CgroupSummarys = append(CgroupSummarys, *CgroupSummary) + } + + err := scanner.Err() + return CgroupSummarys, err +} + +// CgroupSummarys returns information about current /proc/cgroups. +func (fs FS) CgroupSummarys() ([]CgroupSummary, error) { + data, err := util.ReadFileNoStat(fs.proc.Path("cgroups")) + if err != nil { + return nil, err + } + return parseCgroupSummary(data) +} diff --git a/vendor/github.com/prometheus/procfs/proc_environ.go b/vendor/github.com/prometheus/procfs/proc_environ.go index 6134b3580..57a89895d 100644 --- a/vendor/github.com/prometheus/procfs/proc_environ.go +++ b/vendor/github.com/prometheus/procfs/proc_environ.go @@ -19,7 +19,7 @@ import ( "github.com/prometheus/procfs/internal/util" ) -// Environ reads process environments from /proc//environ +// Environ reads process environments from `/proc//environ`. func (p Proc) Environ() ([]string, error) { environments := make([]string, 0) diff --git a/vendor/github.com/prometheus/procfs/proc_fdinfo.go b/vendor/github.com/prometheus/procfs/proc_fdinfo.go index cf63227f0..1bbdd4a8e 100644 --- a/vendor/github.com/prometheus/procfs/proc_fdinfo.go +++ b/vendor/github.com/prometheus/procfs/proc_fdinfo.go @@ -22,7 +22,6 @@ import ( "github.com/prometheus/procfs/internal/util" ) -// Regexp variables var ( rPos = regexp.MustCompile(`^pos:\s+(\d+)$`) rFlags = regexp.MustCompile(`^flags:\s+(\d+)$`) @@ -122,7 +121,7 @@ func (p ProcFDInfos) Len() int { return len(p) } func (p ProcFDInfos) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p ProcFDInfos) Less(i, j int) bool { return p[i].FD < p[j].FD } -// InotifyWatchLen returns the total number of inotify watches +// InotifyWatchLen returns the total number of inotify watches. func (p ProcFDInfos) InotifyWatchLen() (int, error) { length := 0 for _, f := range p { diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go index dd20f198a..7a1388185 100644 --- a/vendor/github.com/prometheus/procfs/proc_limits.go +++ b/vendor/github.com/prometheus/procfs/proc_limits.go @@ -79,7 +79,7 @@ var ( // NewLimits returns the current soft limits of the process. // -// Deprecated: use p.Limits() instead +// Deprecated: Use p.Limits() instead. func (p Proc) NewLimits() (ProcLimits, error) { return p.Limits() } diff --git a/vendor/github.com/prometheus/procfs/proc_maps.go b/vendor/github.com/prometheus/procfs/proc_maps.go index 1d7772d51..f1bcbf32b 100644 --- a/vendor/github.com/prometheus/procfs/proc_maps.go +++ b/vendor/github.com/prometheus/procfs/proc_maps.go @@ -11,7 +11,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) && !js // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris +// +build !js package procfs @@ -25,7 +27,7 @@ import ( "golang.org/x/sys/unix" ) -// ProcMapPermissions contains permission settings read from /proc/[pid]/maps +// ProcMapPermissions contains permission settings read from `/proc/[pid]/maps`. type ProcMapPermissions struct { // mapping has the [R]ead flag set Read bool @@ -39,8 +41,8 @@ type ProcMapPermissions struct { Private bool } -// ProcMap contains the process memory-mappings of the process, -// read from /proc/[pid]/maps +// ProcMap contains the process memory-mappings of the process +// read from `/proc/[pid]/maps`. type ProcMap struct { // The start address of current mapping. StartAddr uintptr @@ -79,7 +81,7 @@ func parseDevice(s string) (uint64, error) { return unix.Mkdev(uint32(major), uint32(minor)), nil } -// parseAddress just converts a hex-string to a uintptr +// parseAddress converts a hex-string to a uintptr. func parseAddress(s string) (uintptr, error) { a, err := strconv.ParseUint(s, 16, 0) if err != nil { @@ -89,7 +91,7 @@ func parseAddress(s string) (uintptr, error) { return uintptr(a), nil } -// parseAddresses parses the start-end address +// parseAddresses parses the start-end address. func parseAddresses(s string) (uintptr, uintptr, error) { toks := strings.Split(s, "-") if len(toks) < 2 { diff --git a/vendor/github.com/prometheus/procfs/proc_netstat.go b/vendor/github.com/prometheus/procfs/proc_netstat.go new file mode 100644 index 000000000..48b523819 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_netstat.go @@ -0,0 +1,440 @@ +// Copyright 2022 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 procfs + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// ProcNetstat models the content of /proc//net/netstat. +type ProcNetstat struct { + // The process ID. + PID int + TcpExt + IpExt +} + +type TcpExt struct { // nolint:revive + SyncookiesSent float64 + SyncookiesRecv float64 + SyncookiesFailed float64 + EmbryonicRsts float64 + PruneCalled float64 + RcvPruned float64 + OfoPruned float64 + OutOfWindowIcmps float64 + LockDroppedIcmps float64 + ArpFilter float64 + TW float64 + TWRecycled float64 + TWKilled float64 + PAWSActive float64 + PAWSEstab float64 + DelayedACKs float64 + DelayedACKLocked float64 + DelayedACKLost float64 + ListenOverflows float64 + ListenDrops float64 + TCPHPHits float64 + TCPPureAcks float64 + TCPHPAcks float64 + TCPRenoRecovery float64 + TCPSackRecovery float64 + TCPSACKReneging float64 + TCPSACKReorder float64 + TCPRenoReorder float64 + TCPTSReorder float64 + TCPFullUndo float64 + TCPPartialUndo float64 + TCPDSACKUndo float64 + TCPLossUndo float64 + TCPLostRetransmit float64 + TCPRenoFailures float64 + TCPSackFailures float64 + TCPLossFailures float64 + TCPFastRetrans float64 + TCPSlowStartRetrans float64 + TCPTimeouts float64 + TCPLossProbes float64 + TCPLossProbeRecovery float64 + TCPRenoRecoveryFail float64 + TCPSackRecoveryFail float64 + TCPRcvCollapsed float64 + TCPDSACKOldSent float64 + TCPDSACKOfoSent float64 + TCPDSACKRecv float64 + TCPDSACKOfoRecv float64 + TCPAbortOnData float64 + TCPAbortOnClose float64 + TCPAbortOnMemory float64 + TCPAbortOnTimeout float64 + TCPAbortOnLinger float64 + TCPAbortFailed float64 + TCPMemoryPressures float64 + TCPMemoryPressuresChrono float64 + TCPSACKDiscard float64 + TCPDSACKIgnoredOld float64 + TCPDSACKIgnoredNoUndo float64 + TCPSpuriousRTOs float64 + TCPMD5NotFound float64 + TCPMD5Unexpected float64 + TCPMD5Failure float64 + TCPSackShifted float64 + TCPSackMerged float64 + TCPSackShiftFallback float64 + TCPBacklogDrop float64 + PFMemallocDrop float64 + TCPMinTTLDrop float64 + TCPDeferAcceptDrop float64 + IPReversePathFilter float64 + TCPTimeWaitOverflow float64 + TCPReqQFullDoCookies float64 + TCPReqQFullDrop float64 + TCPRetransFail float64 + TCPRcvCoalesce float64 + TCPOFOQueue float64 + TCPOFODrop float64 + TCPOFOMerge float64 + TCPChallengeACK float64 + TCPSYNChallenge float64 + TCPFastOpenActive float64 + TCPFastOpenActiveFail float64 + TCPFastOpenPassive float64 + TCPFastOpenPassiveFail float64 + TCPFastOpenListenOverflow float64 + TCPFastOpenCookieReqd float64 + TCPFastOpenBlackhole float64 + TCPSpuriousRtxHostQueues float64 + BusyPollRxPackets float64 + TCPAutoCorking float64 + TCPFromZeroWindowAdv float64 + TCPToZeroWindowAdv float64 + TCPWantZeroWindowAdv float64 + TCPSynRetrans float64 + TCPOrigDataSent float64 + TCPHystartTrainDetect float64 + TCPHystartTrainCwnd float64 + TCPHystartDelayDetect float64 + TCPHystartDelayCwnd float64 + TCPACKSkippedSynRecv float64 + TCPACKSkippedPAWS float64 + TCPACKSkippedSeq float64 + TCPACKSkippedFinWait2 float64 + TCPACKSkippedTimeWait float64 + TCPACKSkippedChallenge float64 + TCPWinProbe float64 + TCPKeepAlive float64 + TCPMTUPFail float64 + TCPMTUPSuccess float64 + TCPWqueueTooBig float64 +} + +type IpExt struct { // nolint:revive + InNoRoutes float64 + InTruncatedPkts float64 + InMcastPkts float64 + OutMcastPkts float64 + InBcastPkts float64 + OutBcastPkts float64 + InOctets float64 + OutOctets float64 + InMcastOctets float64 + OutMcastOctets float64 + InBcastOctets float64 + OutBcastOctets float64 + InCsumErrors float64 + InNoECTPkts float64 + InECT1Pkts float64 + InECT0Pkts float64 + InCEPkts float64 + ReasmOverlaps float64 +} + +func (p Proc) Netstat() (ProcNetstat, error) { + filename := p.path("net/netstat") + data, err := util.ReadFileNoStat(filename) + if err != nil { + return ProcNetstat{PID: p.PID}, err + } + procNetstat, err := parseNetstat(bytes.NewReader(data), filename) + procNetstat.PID = p.PID + return procNetstat, err +} + +// parseNetstat parses the metrics from proc//net/netstat file +// and returns a ProcNetstat structure. +func parseNetstat(r io.Reader, fileName string) (ProcNetstat, error) { + var ( + scanner = bufio.NewScanner(r) + procNetstat = ProcNetstat{} + ) + + for scanner.Scan() { + nameParts := strings.Split(scanner.Text(), " ") + scanner.Scan() + valueParts := strings.Split(scanner.Text(), " ") + // Remove trailing :. + protocol := strings.TrimSuffix(nameParts[0], ":") + if len(nameParts) != len(valueParts) { + return procNetstat, fmt.Errorf("mismatch field count mismatch in %s: %s", + fileName, protocol) + } + for i := 1; i < len(nameParts); i++ { + value, err := strconv.ParseFloat(valueParts[i], 64) + if err != nil { + return procNetstat, err + } + key := nameParts[i] + + switch protocol { + case "TcpExt": + switch key { + case "SyncookiesSent": + procNetstat.TcpExt.SyncookiesSent = value + case "SyncookiesRecv": + procNetstat.TcpExt.SyncookiesRecv = value + case "SyncookiesFailed": + procNetstat.TcpExt.SyncookiesFailed = value + case "EmbryonicRsts": + procNetstat.TcpExt.EmbryonicRsts = value + case "PruneCalled": + procNetstat.TcpExt.PruneCalled = value + case "RcvPruned": + procNetstat.TcpExt.RcvPruned = value + case "OfoPruned": + procNetstat.TcpExt.OfoPruned = value + case "OutOfWindowIcmps": + procNetstat.TcpExt.OutOfWindowIcmps = value + case "LockDroppedIcmps": + procNetstat.TcpExt.LockDroppedIcmps = value + case "ArpFilter": + procNetstat.TcpExt.ArpFilter = value + case "TW": + procNetstat.TcpExt.TW = value + case "TWRecycled": + procNetstat.TcpExt.TWRecycled = value + case "TWKilled": + procNetstat.TcpExt.TWKilled = value + case "PAWSActive": + procNetstat.TcpExt.PAWSActive = value + case "PAWSEstab": + procNetstat.TcpExt.PAWSEstab = value + case "DelayedACKs": + procNetstat.TcpExt.DelayedACKs = value + case "DelayedACKLocked": + procNetstat.TcpExt.DelayedACKLocked = value + case "DelayedACKLost": + procNetstat.TcpExt.DelayedACKLost = value + case "ListenOverflows": + procNetstat.TcpExt.ListenOverflows = value + case "ListenDrops": + procNetstat.TcpExt.ListenDrops = value + case "TCPHPHits": + procNetstat.TcpExt.TCPHPHits = value + case "TCPPureAcks": + procNetstat.TcpExt.TCPPureAcks = value + case "TCPHPAcks": + procNetstat.TcpExt.TCPHPAcks = value + case "TCPRenoRecovery": + procNetstat.TcpExt.TCPRenoRecovery = value + case "TCPSackRecovery": + procNetstat.TcpExt.TCPSackRecovery = value + case "TCPSACKReneging": + procNetstat.TcpExt.TCPSACKReneging = value + case "TCPSACKReorder": + procNetstat.TcpExt.TCPSACKReorder = value + case "TCPRenoReorder": + procNetstat.TcpExt.TCPRenoReorder = value + case "TCPTSReorder": + procNetstat.TcpExt.TCPTSReorder = value + case "TCPFullUndo": + procNetstat.TcpExt.TCPFullUndo = value + case "TCPPartialUndo": + procNetstat.TcpExt.TCPPartialUndo = value + case "TCPDSACKUndo": + procNetstat.TcpExt.TCPDSACKUndo = value + case "TCPLossUndo": + procNetstat.TcpExt.TCPLossUndo = value + case "TCPLostRetransmit": + procNetstat.TcpExt.TCPLostRetransmit = value + case "TCPRenoFailures": + procNetstat.TcpExt.TCPRenoFailures = value + case "TCPSackFailures": + procNetstat.TcpExt.TCPSackFailures = value + case "TCPLossFailures": + procNetstat.TcpExt.TCPLossFailures = value + case "TCPFastRetrans": + procNetstat.TcpExt.TCPFastRetrans = value + case "TCPSlowStartRetrans": + procNetstat.TcpExt.TCPSlowStartRetrans = value + case "TCPTimeouts": + procNetstat.TcpExt.TCPTimeouts = value + case "TCPLossProbes": + procNetstat.TcpExt.TCPLossProbes = value + case "TCPLossProbeRecovery": + procNetstat.TcpExt.TCPLossProbeRecovery = value + case "TCPRenoRecoveryFail": + procNetstat.TcpExt.TCPRenoRecoveryFail = value + case "TCPSackRecoveryFail": + procNetstat.TcpExt.TCPSackRecoveryFail = value + case "TCPRcvCollapsed": + procNetstat.TcpExt.TCPRcvCollapsed = value + case "TCPDSACKOldSent": + procNetstat.TcpExt.TCPDSACKOldSent = value + case "TCPDSACKOfoSent": + procNetstat.TcpExt.TCPDSACKOfoSent = value + case "TCPDSACKRecv": + procNetstat.TcpExt.TCPDSACKRecv = value + case "TCPDSACKOfoRecv": + procNetstat.TcpExt.TCPDSACKOfoRecv = value + case "TCPAbortOnData": + procNetstat.TcpExt.TCPAbortOnData = value + case "TCPAbortOnClose": + procNetstat.TcpExt.TCPAbortOnClose = value + case "TCPDeferAcceptDrop": + procNetstat.TcpExt.TCPDeferAcceptDrop = value + case "IPReversePathFilter": + procNetstat.TcpExt.IPReversePathFilter = value + case "TCPTimeWaitOverflow": + procNetstat.TcpExt.TCPTimeWaitOverflow = value + case "TCPReqQFullDoCookies": + procNetstat.TcpExt.TCPReqQFullDoCookies = value + case "TCPReqQFullDrop": + procNetstat.TcpExt.TCPReqQFullDrop = value + case "TCPRetransFail": + procNetstat.TcpExt.TCPRetransFail = value + case "TCPRcvCoalesce": + procNetstat.TcpExt.TCPRcvCoalesce = value + case "TCPOFOQueue": + procNetstat.TcpExt.TCPOFOQueue = value + case "TCPOFODrop": + procNetstat.TcpExt.TCPOFODrop = value + case "TCPOFOMerge": + procNetstat.TcpExt.TCPOFOMerge = value + case "TCPChallengeACK": + procNetstat.TcpExt.TCPChallengeACK = value + case "TCPSYNChallenge": + procNetstat.TcpExt.TCPSYNChallenge = value + case "TCPFastOpenActive": + procNetstat.TcpExt.TCPFastOpenActive = value + case "TCPFastOpenActiveFail": + procNetstat.TcpExt.TCPFastOpenActiveFail = value + case "TCPFastOpenPassive": + procNetstat.TcpExt.TCPFastOpenPassive = value + case "TCPFastOpenPassiveFail": + procNetstat.TcpExt.TCPFastOpenPassiveFail = value + case "TCPFastOpenListenOverflow": + procNetstat.TcpExt.TCPFastOpenListenOverflow = value + case "TCPFastOpenCookieReqd": + procNetstat.TcpExt.TCPFastOpenCookieReqd = value + case "TCPFastOpenBlackhole": + procNetstat.TcpExt.TCPFastOpenBlackhole = value + case "TCPSpuriousRtxHostQueues": + procNetstat.TcpExt.TCPSpuriousRtxHostQueues = value + case "BusyPollRxPackets": + procNetstat.TcpExt.BusyPollRxPackets = value + case "TCPAutoCorking": + procNetstat.TcpExt.TCPAutoCorking = value + case "TCPFromZeroWindowAdv": + procNetstat.TcpExt.TCPFromZeroWindowAdv = value + case "TCPToZeroWindowAdv": + procNetstat.TcpExt.TCPToZeroWindowAdv = value + case "TCPWantZeroWindowAdv": + procNetstat.TcpExt.TCPWantZeroWindowAdv = value + case "TCPSynRetrans": + procNetstat.TcpExt.TCPSynRetrans = value + case "TCPOrigDataSent": + procNetstat.TcpExt.TCPOrigDataSent = value + case "TCPHystartTrainDetect": + procNetstat.TcpExt.TCPHystartTrainDetect = value + case "TCPHystartTrainCwnd": + procNetstat.TcpExt.TCPHystartTrainCwnd = value + case "TCPHystartDelayDetect": + procNetstat.TcpExt.TCPHystartDelayDetect = value + case "TCPHystartDelayCwnd": + procNetstat.TcpExt.TCPHystartDelayCwnd = value + case "TCPACKSkippedSynRecv": + procNetstat.TcpExt.TCPACKSkippedSynRecv = value + case "TCPACKSkippedPAWS": + procNetstat.TcpExt.TCPACKSkippedPAWS = value + case "TCPACKSkippedSeq": + procNetstat.TcpExt.TCPACKSkippedSeq = value + case "TCPACKSkippedFinWait2": + procNetstat.TcpExt.TCPACKSkippedFinWait2 = value + case "TCPACKSkippedTimeWait": + procNetstat.TcpExt.TCPACKSkippedTimeWait = value + case "TCPACKSkippedChallenge": + procNetstat.TcpExt.TCPACKSkippedChallenge = value + case "TCPWinProbe": + procNetstat.TcpExt.TCPWinProbe = value + case "TCPKeepAlive": + procNetstat.TcpExt.TCPKeepAlive = value + case "TCPMTUPFail": + procNetstat.TcpExt.TCPMTUPFail = value + case "TCPMTUPSuccess": + procNetstat.TcpExt.TCPMTUPSuccess = value + case "TCPWqueueTooBig": + procNetstat.TcpExt.TCPWqueueTooBig = value + } + case "IpExt": + switch key { + case "InNoRoutes": + procNetstat.IpExt.InNoRoutes = value + case "InTruncatedPkts": + procNetstat.IpExt.InTruncatedPkts = value + case "InMcastPkts": + procNetstat.IpExt.InMcastPkts = value + case "OutMcastPkts": + procNetstat.IpExt.OutMcastPkts = value + case "InBcastPkts": + procNetstat.IpExt.InBcastPkts = value + case "OutBcastPkts": + procNetstat.IpExt.OutBcastPkts = value + case "InOctets": + procNetstat.IpExt.InOctets = value + case "OutOctets": + procNetstat.IpExt.OutOctets = value + case "InMcastOctets": + procNetstat.IpExt.InMcastOctets = value + case "OutMcastOctets": + procNetstat.IpExt.OutMcastOctets = value + case "InBcastOctets": + procNetstat.IpExt.InBcastOctets = value + case "OutBcastOctets": + procNetstat.IpExt.OutBcastOctets = value + case "InCsumErrors": + procNetstat.IpExt.InCsumErrors = value + case "InNoECTPkts": + procNetstat.IpExt.InNoECTPkts = value + case "InECT1Pkts": + procNetstat.IpExt.InECT1Pkts = value + case "InECT0Pkts": + procNetstat.IpExt.InECT0Pkts = value + case "InCEPkts": + procNetstat.IpExt.InCEPkts = value + case "ReasmOverlaps": + procNetstat.IpExt.ReasmOverlaps = value + } + } + } + } + return procNetstat, scanner.Err() +} diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go index dc6c14f0a..a68fe1529 100644 --- a/vendor/github.com/prometheus/procfs/proc_psi.go +++ b/vendor/github.com/prometheus/procfs/proc_psi.go @@ -35,9 +35,10 @@ import ( const lineFormat = "avg10=%f avg60=%f avg300=%f total=%d" -// PSILine is a single line of values as returned by /proc/pressure/* -// The Avg entries are averages over n seconds, as a percentage -// The Total line is in microseconds +// PSILine is a single line of values as returned by `/proc/pressure/*`. +// +// The Avg entries are averages over n seconds, as a percentage. +// The Total line is in microseconds. type PSILine struct { Avg10 float64 Avg60 float64 @@ -46,8 +47,9 @@ type PSILine struct { } // PSIStats represent pressure stall information from /proc/pressure/* -// Some indicates the share of time in which at least some tasks are stalled -// Full indicates the share of time in which all non-idle tasks are stalled simultaneously +// +// "Some" indicates the share of time in which at least some tasks are stalled. +// "Full" indicates the share of time in which all non-idle tasks are stalled simultaneously. type PSIStats struct { Some *PSILine Full *PSILine @@ -65,7 +67,7 @@ func (fs FS) PSIStatsForResource(resource string) (PSIStats, error) { return parsePSIStats(resource, bytes.NewReader(data)) } -// parsePSIStats parses the specified file for pressure stall information +// parsePSIStats parses the specified file for pressure stall information. func parsePSIStats(resource string, r io.Reader) (PSIStats, error) { psiStats := PSIStats{} diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go index a576a720a..0e97d9957 100644 --- a/vendor/github.com/prometheus/procfs/proc_smaps.go +++ b/vendor/github.com/prometheus/procfs/proc_smaps.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !windows // +build !windows package procfs @@ -28,30 +29,30 @@ import ( ) var ( - // match the header line before each mapped zone in /proc/pid/smaps + // match the header line before each mapped zone in `/proc/pid/smaps`. procSMapsHeaderLine = regexp.MustCompile(`^[a-f0-9].*$`) ) type ProcSMapsRollup struct { - // Amount of the mapping that is currently resident in RAM + // Amount of the mapping that is currently resident in RAM. Rss uint64 - // Process's proportional share of this mapping + // Process's proportional share of this mapping. Pss uint64 - // Size in bytes of clean shared pages + // Size in bytes of clean shared pages. SharedClean uint64 - // Size in bytes of dirty shared pages + // Size in bytes of dirty shared pages. SharedDirty uint64 - // Size in bytes of clean private pages + // Size in bytes of clean private pages. PrivateClean uint64 - // Size in bytes of dirty private pages + // Size in bytes of dirty private pages. PrivateDirty uint64 - // Amount of memory currently marked as referenced or accessed + // Amount of memory currently marked as referenced or accessed. Referenced uint64 - // Amount of memory that does not belong to any file + // Amount of memory that does not belong to any file. Anonymous uint64 - // Amount would-be-anonymous memory currently on swap + // Amount would-be-anonymous memory currently on swap. Swap uint64 - // Process's proportional memory on swap + // Process's proportional memory on swap. SwapPss uint64 } diff --git a/vendor/github.com/prometheus/procfs/proc_snmp.go b/vendor/github.com/prometheus/procfs/proc_snmp.go new file mode 100644 index 000000000..ae191896c --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_snmp.go @@ -0,0 +1,353 @@ +// Copyright 2022 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 procfs + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// ProcSnmp models the content of /proc//net/snmp. +type ProcSnmp struct { + // The process ID. + PID int + Ip + Icmp + IcmpMsg + Tcp + Udp + UdpLite +} + +type Ip struct { // nolint:revive + Forwarding float64 + DefaultTTL float64 + InReceives float64 + InHdrErrors float64 + InAddrErrors float64 + ForwDatagrams float64 + InUnknownProtos float64 + InDiscards float64 + InDelivers float64 + OutRequests float64 + OutDiscards float64 + OutNoRoutes float64 + ReasmTimeout float64 + ReasmReqds float64 + ReasmOKs float64 + ReasmFails float64 + FragOKs float64 + FragFails float64 + FragCreates float64 +} + +type Icmp struct { + InMsgs float64 + InErrors float64 + InCsumErrors float64 + InDestUnreachs float64 + InTimeExcds float64 + InParmProbs float64 + InSrcQuenchs float64 + InRedirects float64 + InEchos float64 + InEchoReps float64 + InTimestamps float64 + InTimestampReps float64 + InAddrMasks float64 + InAddrMaskReps float64 + OutMsgs float64 + OutErrors float64 + OutDestUnreachs float64 + OutTimeExcds float64 + OutParmProbs float64 + OutSrcQuenchs float64 + OutRedirects float64 + OutEchos float64 + OutEchoReps float64 + OutTimestamps float64 + OutTimestampReps float64 + OutAddrMasks float64 + OutAddrMaskReps float64 +} + +type IcmpMsg struct { + InType3 float64 + OutType3 float64 +} + +type Tcp struct { // nolint:revive + RtoAlgorithm float64 + RtoMin float64 + RtoMax float64 + MaxConn float64 + ActiveOpens float64 + PassiveOpens float64 + AttemptFails float64 + EstabResets float64 + CurrEstab float64 + InSegs float64 + OutSegs float64 + RetransSegs float64 + InErrs float64 + OutRsts float64 + InCsumErrors float64 +} + +type Udp struct { // nolint:revive + InDatagrams float64 + NoPorts float64 + InErrors float64 + OutDatagrams float64 + RcvbufErrors float64 + SndbufErrors float64 + InCsumErrors float64 + IgnoredMulti float64 +} + +type UdpLite struct { // nolint:revive + InDatagrams float64 + NoPorts float64 + InErrors float64 + OutDatagrams float64 + RcvbufErrors float64 + SndbufErrors float64 + InCsumErrors float64 + IgnoredMulti float64 +} + +func (p Proc) Snmp() (ProcSnmp, error) { + filename := p.path("net/snmp") + data, err := util.ReadFileNoStat(filename) + if err != nil { + return ProcSnmp{PID: p.PID}, err + } + procSnmp, err := parseSnmp(bytes.NewReader(data), filename) + procSnmp.PID = p.PID + return procSnmp, err +} + +// parseSnmp parses the metrics from proc//net/snmp file +// and returns a map contains those metrics (e.g. {"Ip": {"Forwarding": 2}}). +func parseSnmp(r io.Reader, fileName string) (ProcSnmp, error) { + var ( + scanner = bufio.NewScanner(r) + procSnmp = ProcSnmp{} + ) + + for scanner.Scan() { + nameParts := strings.Split(scanner.Text(), " ") + scanner.Scan() + valueParts := strings.Split(scanner.Text(), " ") + // Remove trailing :. + protocol := strings.TrimSuffix(nameParts[0], ":") + if len(nameParts) != len(valueParts) { + return procSnmp, fmt.Errorf("mismatch field count mismatch in %s: %s", + fileName, protocol) + } + for i := 1; i < len(nameParts); i++ { + value, err := strconv.ParseFloat(valueParts[i], 64) + if err != nil { + return procSnmp, err + } + key := nameParts[i] + + switch protocol { + case "Ip": + switch key { + case "Forwarding": + procSnmp.Ip.Forwarding = value + case "DefaultTTL": + procSnmp.Ip.DefaultTTL = value + case "InReceives": + procSnmp.Ip.InReceives = value + case "InHdrErrors": + procSnmp.Ip.InHdrErrors = value + case "InAddrErrors": + procSnmp.Ip.InAddrErrors = value + case "ForwDatagrams": + procSnmp.Ip.ForwDatagrams = value + case "InUnknownProtos": + procSnmp.Ip.InUnknownProtos = value + case "InDiscards": + procSnmp.Ip.InDiscards = value + case "InDelivers": + procSnmp.Ip.InDelivers = value + case "OutRequests": + procSnmp.Ip.OutRequests = value + case "OutDiscards": + procSnmp.Ip.OutDiscards = value + case "OutNoRoutes": + procSnmp.Ip.OutNoRoutes = value + case "ReasmTimeout": + procSnmp.Ip.ReasmTimeout = value + case "ReasmReqds": + procSnmp.Ip.ReasmReqds = value + case "ReasmOKs": + procSnmp.Ip.ReasmOKs = value + case "ReasmFails": + procSnmp.Ip.ReasmFails = value + case "FragOKs": + procSnmp.Ip.FragOKs = value + case "FragFails": + procSnmp.Ip.FragFails = value + case "FragCreates": + procSnmp.Ip.FragCreates = value + } + case "Icmp": + switch key { + case "InMsgs": + procSnmp.Icmp.InMsgs = value + case "InErrors": + procSnmp.Icmp.InErrors = value + case "InCsumErrors": + procSnmp.Icmp.InCsumErrors = value + case "InDestUnreachs": + procSnmp.Icmp.InDestUnreachs = value + case "InTimeExcds": + procSnmp.Icmp.InTimeExcds = value + case "InParmProbs": + procSnmp.Icmp.InParmProbs = value + case "InSrcQuenchs": + procSnmp.Icmp.InSrcQuenchs = value + case "InRedirects": + procSnmp.Icmp.InRedirects = value + case "InEchos": + procSnmp.Icmp.InEchos = value + case "InEchoReps": + procSnmp.Icmp.InEchoReps = value + case "InTimestamps": + procSnmp.Icmp.InTimestamps = value + case "InTimestampReps": + procSnmp.Icmp.InTimestampReps = value + case "InAddrMasks": + procSnmp.Icmp.InAddrMasks = value + case "InAddrMaskReps": + procSnmp.Icmp.InAddrMaskReps = value + case "OutMsgs": + procSnmp.Icmp.OutMsgs = value + case "OutErrors": + procSnmp.Icmp.OutErrors = value + case "OutDestUnreachs": + procSnmp.Icmp.OutDestUnreachs = value + case "OutTimeExcds": + procSnmp.Icmp.OutTimeExcds = value + case "OutParmProbs": + procSnmp.Icmp.OutParmProbs = value + case "OutSrcQuenchs": + procSnmp.Icmp.OutSrcQuenchs = value + case "OutRedirects": + procSnmp.Icmp.OutRedirects = value + case "OutEchos": + procSnmp.Icmp.OutEchos = value + case "OutEchoReps": + procSnmp.Icmp.OutEchoReps = value + case "OutTimestamps": + procSnmp.Icmp.OutTimestamps = value + case "OutTimestampReps": + procSnmp.Icmp.OutTimestampReps = value + case "OutAddrMasks": + procSnmp.Icmp.OutAddrMasks = value + case "OutAddrMaskReps": + procSnmp.Icmp.OutAddrMaskReps = value + } + case "IcmpMsg": + switch key { + case "InType3": + procSnmp.IcmpMsg.InType3 = value + case "OutType3": + procSnmp.IcmpMsg.OutType3 = value + } + case "Tcp": + switch key { + case "RtoAlgorithm": + procSnmp.Tcp.RtoAlgorithm = value + case "RtoMin": + procSnmp.Tcp.RtoMin = value + case "RtoMax": + procSnmp.Tcp.RtoMax = value + case "MaxConn": + procSnmp.Tcp.MaxConn = value + case "ActiveOpens": + procSnmp.Tcp.ActiveOpens = value + case "PassiveOpens": + procSnmp.Tcp.PassiveOpens = value + case "AttemptFails": + procSnmp.Tcp.AttemptFails = value + case "EstabResets": + procSnmp.Tcp.EstabResets = value + case "CurrEstab": + procSnmp.Tcp.CurrEstab = value + case "InSegs": + procSnmp.Tcp.InSegs = value + case "OutSegs": + procSnmp.Tcp.OutSegs = value + case "RetransSegs": + procSnmp.Tcp.RetransSegs = value + case "InErrs": + procSnmp.Tcp.InErrs = value + case "OutRsts": + procSnmp.Tcp.OutRsts = value + case "InCsumErrors": + procSnmp.Tcp.InCsumErrors = value + } + case "Udp": + switch key { + case "InDatagrams": + procSnmp.Udp.InDatagrams = value + case "NoPorts": + procSnmp.Udp.NoPorts = value + case "InErrors": + procSnmp.Udp.InErrors = value + case "OutDatagrams": + procSnmp.Udp.OutDatagrams = value + case "RcvbufErrors": + procSnmp.Udp.RcvbufErrors = value + case "SndbufErrors": + procSnmp.Udp.SndbufErrors = value + case "InCsumErrors": + procSnmp.Udp.InCsumErrors = value + case "IgnoredMulti": + procSnmp.Udp.IgnoredMulti = value + } + case "UdpLite": + switch key { + case "InDatagrams": + procSnmp.UdpLite.InDatagrams = value + case "NoPorts": + procSnmp.UdpLite.NoPorts = value + case "InErrors": + procSnmp.UdpLite.InErrors = value + case "OutDatagrams": + procSnmp.UdpLite.OutDatagrams = value + case "RcvbufErrors": + procSnmp.UdpLite.RcvbufErrors = value + case "SndbufErrors": + procSnmp.UdpLite.SndbufErrors = value + case "InCsumErrors": + procSnmp.UdpLite.InCsumErrors = value + case "IgnoredMulti": + procSnmp.UdpLite.IgnoredMulti = value + } + } + } + } + return procSnmp, scanner.Err() +} diff --git a/vendor/github.com/prometheus/procfs/proc_snmp6.go b/vendor/github.com/prometheus/procfs/proc_snmp6.go new file mode 100644 index 000000000..f611992d5 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_snmp6.go @@ -0,0 +1,381 @@ +// Copyright 2022 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 procfs + +import ( + "bufio" + "bytes" + "errors" + "io" + "os" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// ProcSnmp6 models the content of /proc//net/snmp6. +type ProcSnmp6 struct { + // The process ID. + PID int + Ip6 + Icmp6 + Udp6 + UdpLite6 +} + +type Ip6 struct { // nolint:revive + InReceives float64 + InHdrErrors float64 + InTooBigErrors float64 + InNoRoutes float64 + InAddrErrors float64 + InUnknownProtos float64 + InTruncatedPkts float64 + InDiscards float64 + InDelivers float64 + OutForwDatagrams float64 + OutRequests float64 + OutDiscards float64 + OutNoRoutes float64 + ReasmTimeout float64 + ReasmReqds float64 + ReasmOKs float64 + ReasmFails float64 + FragOKs float64 + FragFails float64 + FragCreates float64 + InMcastPkts float64 + OutMcastPkts float64 + InOctets float64 + OutOctets float64 + InMcastOctets float64 + OutMcastOctets float64 + InBcastOctets float64 + OutBcastOctets float64 + InNoECTPkts float64 + InECT1Pkts float64 + InECT0Pkts float64 + InCEPkts float64 +} + +type Icmp6 struct { + InMsgs float64 + InErrors float64 + OutMsgs float64 + OutErrors float64 + InCsumErrors float64 + InDestUnreachs float64 + InPktTooBigs float64 + InTimeExcds float64 + InParmProblems float64 + InEchos float64 + InEchoReplies float64 + InGroupMembQueries float64 + InGroupMembResponses float64 + InGroupMembReductions float64 + InRouterSolicits float64 + InRouterAdvertisements float64 + InNeighborSolicits float64 + InNeighborAdvertisements float64 + InRedirects float64 + InMLDv2Reports float64 + OutDestUnreachs float64 + OutPktTooBigs float64 + OutTimeExcds float64 + OutParmProblems float64 + OutEchos float64 + OutEchoReplies float64 + OutGroupMembQueries float64 + OutGroupMembResponses float64 + OutGroupMembReductions float64 + OutRouterSolicits float64 + OutRouterAdvertisements float64 + OutNeighborSolicits float64 + OutNeighborAdvertisements float64 + OutRedirects float64 + OutMLDv2Reports float64 + InType1 float64 + InType134 float64 + InType135 float64 + InType136 float64 + InType143 float64 + OutType133 float64 + OutType135 float64 + OutType136 float64 + OutType143 float64 +} + +type Udp6 struct { // nolint:revive + InDatagrams float64 + NoPorts float64 + InErrors float64 + OutDatagrams float64 + RcvbufErrors float64 + SndbufErrors float64 + InCsumErrors float64 + IgnoredMulti float64 +} + +type UdpLite6 struct { // nolint:revive + InDatagrams float64 + NoPorts float64 + InErrors float64 + OutDatagrams float64 + RcvbufErrors float64 + SndbufErrors float64 + InCsumErrors float64 +} + +func (p Proc) Snmp6() (ProcSnmp6, error) { + filename := p.path("net/snmp6") + data, err := util.ReadFileNoStat(filename) + if err != nil { + // On systems with IPv6 disabled, this file won't exist. + // Do nothing. + if errors.Is(err, os.ErrNotExist) { + return ProcSnmp6{PID: p.PID}, nil + } + + return ProcSnmp6{PID: p.PID}, err + } + + procSnmp6, err := parseSNMP6Stats(bytes.NewReader(data)) + procSnmp6.PID = p.PID + return procSnmp6, err +} + +// parseSnmp6 parses the metrics from proc//net/snmp6 file +// and returns a map contains those metrics. +func parseSNMP6Stats(r io.Reader) (ProcSnmp6, error) { + var ( + scanner = bufio.NewScanner(r) + procSnmp6 = ProcSnmp6{} + ) + + for scanner.Scan() { + stat := strings.Fields(scanner.Text()) + if len(stat) < 2 { + continue + } + // Expect to have "6" in metric name, skip line otherwise + if sixIndex := strings.Index(stat[0], "6"); sixIndex != -1 { + protocol := stat[0][:sixIndex+1] + key := stat[0][sixIndex+1:] + value, err := strconv.ParseFloat(stat[1], 64) + if err != nil { + return procSnmp6, err + } + + switch protocol { + case "Ip6": + switch key { + case "InReceives": + procSnmp6.Ip6.InReceives = value + case "InHdrErrors": + procSnmp6.Ip6.InHdrErrors = value + case "InTooBigErrors": + procSnmp6.Ip6.InTooBigErrors = value + case "InNoRoutes": + procSnmp6.Ip6.InNoRoutes = value + case "InAddrErrors": + procSnmp6.Ip6.InAddrErrors = value + case "InUnknownProtos": + procSnmp6.Ip6.InUnknownProtos = value + case "InTruncatedPkts": + procSnmp6.Ip6.InTruncatedPkts = value + case "InDiscards": + procSnmp6.Ip6.InDiscards = value + case "InDelivers": + procSnmp6.Ip6.InDelivers = value + case "OutForwDatagrams": + procSnmp6.Ip6.OutForwDatagrams = value + case "OutRequests": + procSnmp6.Ip6.OutRequests = value + case "OutDiscards": + procSnmp6.Ip6.OutDiscards = value + case "OutNoRoutes": + procSnmp6.Ip6.OutNoRoutes = value + case "ReasmTimeout": + procSnmp6.Ip6.ReasmTimeout = value + case "ReasmReqds": + procSnmp6.Ip6.ReasmReqds = value + case "ReasmOKs": + procSnmp6.Ip6.ReasmOKs = value + case "ReasmFails": + procSnmp6.Ip6.ReasmFails = value + case "FragOKs": + procSnmp6.Ip6.FragOKs = value + case "FragFails": + procSnmp6.Ip6.FragFails = value + case "FragCreates": + procSnmp6.Ip6.FragCreates = value + case "InMcastPkts": + procSnmp6.Ip6.InMcastPkts = value + case "OutMcastPkts": + procSnmp6.Ip6.OutMcastPkts = value + case "InOctets": + procSnmp6.Ip6.InOctets = value + case "OutOctets": + procSnmp6.Ip6.OutOctets = value + case "InMcastOctets": + procSnmp6.Ip6.InMcastOctets = value + case "OutMcastOctets": + procSnmp6.Ip6.OutMcastOctets = value + case "InBcastOctets": + procSnmp6.Ip6.InBcastOctets = value + case "OutBcastOctets": + procSnmp6.Ip6.OutBcastOctets = value + case "InNoECTPkts": + procSnmp6.Ip6.InNoECTPkts = value + case "InECT1Pkts": + procSnmp6.Ip6.InECT1Pkts = value + case "InECT0Pkts": + procSnmp6.Ip6.InECT0Pkts = value + case "InCEPkts": + procSnmp6.Ip6.InCEPkts = value + + } + case "Icmp6": + switch key { + case "InMsgs": + procSnmp6.Icmp6.InMsgs = value + case "InErrors": + procSnmp6.Icmp6.InErrors = value + case "OutMsgs": + procSnmp6.Icmp6.OutMsgs = value + case "OutErrors": + procSnmp6.Icmp6.OutErrors = value + case "InCsumErrors": + procSnmp6.Icmp6.InCsumErrors = value + case "InDestUnreachs": + procSnmp6.Icmp6.InDestUnreachs = value + case "InPktTooBigs": + procSnmp6.Icmp6.InPktTooBigs = value + case "InTimeExcds": + procSnmp6.Icmp6.InTimeExcds = value + case "InParmProblems": + procSnmp6.Icmp6.InParmProblems = value + case "InEchos": + procSnmp6.Icmp6.InEchos = value + case "InEchoReplies": + procSnmp6.Icmp6.InEchoReplies = value + case "InGroupMembQueries": + procSnmp6.Icmp6.InGroupMembQueries = value + case "InGroupMembResponses": + procSnmp6.Icmp6.InGroupMembResponses = value + case "InGroupMembReductions": + procSnmp6.Icmp6.InGroupMembReductions = value + case "InRouterSolicits": + procSnmp6.Icmp6.InRouterSolicits = value + case "InRouterAdvertisements": + procSnmp6.Icmp6.InRouterAdvertisements = value + case "InNeighborSolicits": + procSnmp6.Icmp6.InNeighborSolicits = value + case "InNeighborAdvertisements": + procSnmp6.Icmp6.InNeighborAdvertisements = value + case "InRedirects": + procSnmp6.Icmp6.InRedirects = value + case "InMLDv2Reports": + procSnmp6.Icmp6.InMLDv2Reports = value + case "OutDestUnreachs": + procSnmp6.Icmp6.OutDestUnreachs = value + case "OutPktTooBigs": + procSnmp6.Icmp6.OutPktTooBigs = value + case "OutTimeExcds": + procSnmp6.Icmp6.OutTimeExcds = value + case "OutParmProblems": + procSnmp6.Icmp6.OutParmProblems = value + case "OutEchos": + procSnmp6.Icmp6.OutEchos = value + case "OutEchoReplies": + procSnmp6.Icmp6.OutEchoReplies = value + case "OutGroupMembQueries": + procSnmp6.Icmp6.OutGroupMembQueries = value + case "OutGroupMembResponses": + procSnmp6.Icmp6.OutGroupMembResponses = value + case "OutGroupMembReductions": + procSnmp6.Icmp6.OutGroupMembReductions = value + case "OutRouterSolicits": + procSnmp6.Icmp6.OutRouterSolicits = value + case "OutRouterAdvertisements": + procSnmp6.Icmp6.OutRouterAdvertisements = value + case "OutNeighborSolicits": + procSnmp6.Icmp6.OutNeighborSolicits = value + case "OutNeighborAdvertisements": + procSnmp6.Icmp6.OutNeighborAdvertisements = value + case "OutRedirects": + procSnmp6.Icmp6.OutRedirects = value + case "OutMLDv2Reports": + procSnmp6.Icmp6.OutMLDv2Reports = value + case "InType1": + procSnmp6.Icmp6.InType1 = value + case "InType134": + procSnmp6.Icmp6.InType134 = value + case "InType135": + procSnmp6.Icmp6.InType135 = value + case "InType136": + procSnmp6.Icmp6.InType136 = value + case "InType143": + procSnmp6.Icmp6.InType143 = value + case "OutType133": + procSnmp6.Icmp6.OutType133 = value + case "OutType135": + procSnmp6.Icmp6.OutType135 = value + case "OutType136": + procSnmp6.Icmp6.OutType136 = value + case "OutType143": + procSnmp6.Icmp6.OutType143 = value + } + case "Udp6": + switch key { + case "InDatagrams": + procSnmp6.Udp6.InDatagrams = value + case "NoPorts": + procSnmp6.Udp6.NoPorts = value + case "InErrors": + procSnmp6.Udp6.InErrors = value + case "OutDatagrams": + procSnmp6.Udp6.OutDatagrams = value + case "RcvbufErrors": + procSnmp6.Udp6.RcvbufErrors = value + case "SndbufErrors": + procSnmp6.Udp6.SndbufErrors = value + case "InCsumErrors": + procSnmp6.Udp6.InCsumErrors = value + case "IgnoredMulti": + procSnmp6.Udp6.IgnoredMulti = value + } + case "UdpLite6": + switch key { + case "InDatagrams": + procSnmp6.UdpLite6.InDatagrams = value + case "NoPorts": + procSnmp6.UdpLite6.NoPorts = value + case "InErrors": + procSnmp6.UdpLite6.InErrors = value + case "OutDatagrams": + procSnmp6.UdpLite6.OutDatagrams = value + case "RcvbufErrors": + procSnmp6.UdpLite6.RcvbufErrors = value + case "SndbufErrors": + procSnmp6.UdpLite6.SndbufErrors = value + case "InCsumErrors": + procSnmp6.UdpLite6.InCsumErrors = value + } + } + } + } + return procSnmp6, scanner.Err() +} diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 8c7b6e80a..06c556ef9 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -81,10 +81,10 @@ type ProcStat struct { STime uint // Amount of time that this process's waited-for children have been // scheduled in user mode, measured in clock ticks. - CUTime uint + CUTime int // Amount of time that this process's waited-for children have been // scheduled in kernel mode, measured in clock ticks. - CSTime uint + CSTime int // For processes running a real-time scheduling policy, this is the negated // scheduling priority, minus one. Priority int @@ -115,7 +115,7 @@ type ProcStat struct { // NewStat returns the current status information of the process. // -// Deprecated: use p.Stat() instead +// Deprecated: Use p.Stat() instead. func (p Proc) NewStat() (ProcStat, error) { return p.Stat() } @@ -141,6 +141,11 @@ func (p Proc) Stat() (ProcStat, error) { } s.Comm = string(data[l+1 : r]) + + // Check the following resources for the details about the particular stat + // fields and their data types: + // * https://man7.org/linux/man-pages/man5/proc.5.html + // * https://man7.org/linux/man-pages/man3/scanf.3.html _, err = fmt.Fscan( bytes.NewBuffer(data[r+2:]), &s.State, diff --git a/vendor/github.com/prometheus/procfs/proc_status.go b/vendor/github.com/prometheus/procfs/proc_status.go index 6edd8333b..594022ded 100644 --- a/vendor/github.com/prometheus/procfs/proc_status.go +++ b/vendor/github.com/prometheus/procfs/proc_status.go @@ -33,37 +33,37 @@ type ProcStatus struct { TGID int // Peak virtual memory size. - VmPeak uint64 // nolint:golint + VmPeak uint64 // nolint:revive // Virtual memory size. - VmSize uint64 // nolint:golint + VmSize uint64 // nolint:revive // Locked memory size. - VmLck uint64 // nolint:golint + VmLck uint64 // nolint:revive // Pinned memory size. - VmPin uint64 // nolint:golint + VmPin uint64 // nolint:revive // Peak resident set size. - VmHWM uint64 // nolint:golint + VmHWM uint64 // nolint:revive // Resident set size (sum of RssAnnon RssFile and RssShmem). - VmRSS uint64 // nolint:golint + VmRSS uint64 // nolint:revive // Size of resident anonymous memory. - RssAnon uint64 // nolint:golint + RssAnon uint64 // nolint:revive // Size of resident file mappings. - RssFile uint64 // nolint:golint + RssFile uint64 // nolint:revive // Size of resident shared memory. - RssShmem uint64 // nolint:golint + RssShmem uint64 // nolint:revive // Size of data segments. - VmData uint64 // nolint:golint + VmData uint64 // nolint:revive // Size of stack segments. - VmStk uint64 // nolint:golint + VmStk uint64 // nolint:revive // Size of text segments. - VmExe uint64 // nolint:golint + VmExe uint64 // nolint:revive // Shared library code size. - VmLib uint64 // nolint:golint + VmLib uint64 // nolint:revive // Page table entries size. - VmPTE uint64 // nolint:golint + VmPTE uint64 // nolint:revive // Size of second-level page tables. - VmPMD uint64 // nolint:golint + VmPMD uint64 // nolint:revive // Swapped-out virtual memory size by anonymous private. - VmSwap uint64 // nolint:golint + VmSwap uint64 // nolint:revive // Size of hugetlb memory portions HugetlbPages uint64 diff --git a/vendor/github.com/prometheus/procfs/proc_sys.go b/vendor/github.com/prometheus/procfs/proc_sys.go new file mode 100644 index 000000000..d46533ebf --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_sys.go @@ -0,0 +1,51 @@ +// Copyright 2022 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 procfs + +import ( + "fmt" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +func sysctlToPath(sysctl string) string { + return strings.Replace(sysctl, ".", "/", -1) +} + +func (fs FS) SysctlStrings(sysctl string) ([]string, error) { + value, err := util.SysReadFile(fs.proc.Path("sys", sysctlToPath(sysctl))) + if err != nil { + return nil, err + } + return strings.Fields(value), nil + +} + +func (fs FS) SysctlInts(sysctl string) ([]int, error) { + fields, err := fs.SysctlStrings(sysctl) + if err != nil { + return nil, err + } + + values := make([]int, len(fields)) + for i, f := range fields { + vp := util.NewValueParser(f) + values[i] = vp.Int() + if err := vp.Err(); err != nil { + return nil, fmt.Errorf("field %d in sysctl %s is not a valid int: %w", i, sysctl, err) + } + } + return values, nil +} diff --git a/vendor/github.com/prometheus/procfs/schedstat.go b/vendor/github.com/prometheus/procfs/schedstat.go index 28228164e..5f7f32dc8 100644 --- a/vendor/github.com/prometheus/procfs/schedstat.go +++ b/vendor/github.com/prometheus/procfs/schedstat.go @@ -40,7 +40,7 @@ type Schedstat struct { CPUs []*SchedstatCPU } -// SchedstatCPU contains the values from one "cpu" line +// SchedstatCPU contains the values from one "cpu" line. type SchedstatCPU struct { CPUNum string @@ -49,14 +49,14 @@ type SchedstatCPU struct { RunTimeslices uint64 } -// ProcSchedstat contains the values from /proc//schedstat +// ProcSchedstat contains the values from `/proc//schedstat`. type ProcSchedstat struct { RunningNanoseconds uint64 WaitingNanoseconds uint64 RunTimeslices uint64 } -// Schedstat reads data from /proc/schedstat +// Schedstat reads data from `/proc/schedstat`. func (fs FS) Schedstat() (*Schedstat, error) { file, err := os.Open(fs.proc.Path("schedstat")) if err != nil { diff --git a/vendor/github.com/prometheus/procfs/slab.go b/vendor/github.com/prometheus/procfs/slab.go index 7896fd724..bc9aaf5c2 100644 --- a/vendor/github.com/prometheus/procfs/slab.go +++ b/vendor/github.com/prometheus/procfs/slab.go @@ -137,7 +137,7 @@ func parseSlabInfo21(r *bytes.Reader) (SlabInfo, error) { return s, nil } -// SlabInfo reads data from /proc/slabinfo +// SlabInfo reads data from `/proc/slabinfo`. func (fs FS) SlabInfo() (SlabInfo, error) { // TODO: Consider passing options to allow for parsing different // slabinfo versions. However, slabinfo 2.1 has been stable since diff --git a/vendor/github.com/prometheus/procfs/softirqs.go b/vendor/github.com/prometheus/procfs/softirqs.go new file mode 100644 index 000000000..559129cbc --- /dev/null +++ b/vendor/github.com/prometheus/procfs/softirqs.go @@ -0,0 +1,160 @@ +// Copyright 2022 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 procfs + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// Softirqs represents the softirq statistics. +type Softirqs struct { + Hi []uint64 + Timer []uint64 + NetTx []uint64 + NetRx []uint64 + Block []uint64 + IRQPoll []uint64 + Tasklet []uint64 + Sched []uint64 + HRTimer []uint64 + RCU []uint64 +} + +func (fs FS) Softirqs() (Softirqs, error) { + fileName := fs.proc.Path("softirqs") + data, err := util.ReadFileNoStat(fileName) + if err != nil { + return Softirqs{}, err + } + + reader := bytes.NewReader(data) + + return parseSoftirqs(reader) +} + +func parseSoftirqs(r io.Reader) (Softirqs, error) { + var ( + softirqs = Softirqs{} + scanner = bufio.NewScanner(r) + ) + + if !scanner.Scan() { + return Softirqs{}, fmt.Errorf("softirqs empty") + } + + for scanner.Scan() { + parts := strings.Fields(scanner.Text()) + var err error + + // require at least one cpu + if len(parts) < 2 { + continue + } + switch { + case parts[0] == "HI:": + perCPU := parts[1:] + softirqs.Hi = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.Hi[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (HI%d): %w", count, i, err) + } + } + case parts[0] == "TIMER:": + perCPU := parts[1:] + softirqs.Timer = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.Timer[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (TIMER%d): %w", count, i, err) + } + } + case parts[0] == "NET_TX:": + perCPU := parts[1:] + softirqs.NetTx = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.NetTx[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (NET_TX%d): %w", count, i, err) + } + } + case parts[0] == "NET_RX:": + perCPU := parts[1:] + softirqs.NetRx = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.NetRx[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (NET_RX%d): %w", count, i, err) + } + } + case parts[0] == "BLOCK:": + perCPU := parts[1:] + softirqs.Block = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.Block[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (BLOCK%d): %w", count, i, err) + } + } + case parts[0] == "IRQ_POLL:": + perCPU := parts[1:] + softirqs.IRQPoll = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.IRQPoll[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (IRQ_POLL%d): %w", count, i, err) + } + } + case parts[0] == "TASKLET:": + perCPU := parts[1:] + softirqs.Tasklet = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.Tasklet[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (TASKLET%d): %w", count, i, err) + } + } + case parts[0] == "SCHED:": + perCPU := parts[1:] + softirqs.Sched = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.Sched[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (SCHED%d): %w", count, i, err) + } + } + case parts[0] == "HRTIMER:": + perCPU := parts[1:] + softirqs.HRTimer = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.HRTimer[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (HRTIMER%d): %w", count, i, err) + } + } + case parts[0] == "RCU:": + perCPU := parts[1:] + softirqs.RCU = make([]uint64, len(perCPU)) + for i, count := range perCPU { + if softirqs.RCU[i], err = strconv.ParseUint(count, 10, 64); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse %q (RCU%d): %w", count, i, err) + } + } + } + } + + if err := scanner.Err(); err != nil { + return Softirqs{}, fmt.Errorf("couldn't parse softirqs: %w", err) + } + + return softirqs, scanner.Err() +} diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go index 6d8727541..33f97caa0 100644 --- a/vendor/github.com/prometheus/procfs/stat.go +++ b/vendor/github.com/prometheus/procfs/stat.go @@ -41,7 +41,7 @@ type CPUStat struct { // SoftIRQStat represent the softirq statistics as exported in the procfs stat file. // A nice introduction can be found at https://0xax.gitbooks.io/linux-insides/content/interrupts/interrupts-9.html -// It is possible to get per-cpu stats by reading /proc/softirqs +// It is possible to get per-cpu stats by reading `/proc/softirqs`. type SoftIRQStat struct { Hi uint64 Timer uint64 @@ -145,7 +145,7 @@ func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) { // NewStat returns information about current cpu/process statistics. // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt // -// Deprecated: use fs.Stat() instead +// Deprecated: Use fs.Stat() instead. func NewStat() (Stat, error) { fs, err := NewFS(fs.DefaultProcMountPoint) if err != nil { @@ -155,15 +155,15 @@ func NewStat() (Stat, error) { } // NewStat returns information about current cpu/process statistics. -// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt +// See: https://www.kernel.org/doc/Documentation/filesystems/proc.txt // -// Deprecated: use fs.Stat() instead +// Deprecated: Use fs.Stat() instead. func (fs FS) NewStat() (Stat, error) { return fs.Stat() } // Stat returns information about current cpu/process statistics. -// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt +// See: https://www.kernel.org/doc/Documentation/filesystems/proc.txt func (fs FS) Stat() (Stat, error) { fileName := fs.proc.Path("stat") data, err := util.ReadFileNoStat(fileName) diff --git a/vendor/github.com/prometheus/procfs/vm.go b/vendor/github.com/prometheus/procfs/vm.go index cb1389141..20ceb77e2 100644 --- a/vendor/github.com/prometheus/procfs/vm.go +++ b/vendor/github.com/prometheus/procfs/vm.go @@ -11,13 +11,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !windows // +build !windows package procfs import ( "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -29,7 +29,7 @@ import ( // https://www.kernel.org/doc/Documentation/sysctl/vm.txt // Each setting is exposed as a single file. // Each file contains one line with a single numerical value, except lowmem_reserve_ratio which holds an array -// and numa_zonelist_order (deprecated) which is a string +// and numa_zonelist_order (deprecated) which is a string. type VM struct { AdminReserveKbytes *int64 // /proc/sys/vm/admin_reserve_kbytes BlockDump *int64 // /proc/sys/vm/block_dump @@ -87,7 +87,7 @@ func (fs FS) VM() (*VM, error) { return nil, fmt.Errorf("%s is not a directory", path) } - files, err := ioutil.ReadDir(path) + files, err := os.ReadDir(path) if err != nil { return nil, err } diff --git a/vendor/github.com/prometheus/procfs/zoneinfo.go b/vendor/github.com/prometheus/procfs/zoneinfo.go index 209e2ac98..c745a4c04 100644 --- a/vendor/github.com/prometheus/procfs/zoneinfo.go +++ b/vendor/github.com/prometheus/procfs/zoneinfo.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build !windows // +build !windows package procfs @@ -18,7 +19,7 @@ package procfs import ( "bytes" "fmt" - "io/ioutil" + "os" "regexp" "strings" @@ -72,7 +73,7 @@ var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`) // structs containing the relevant info. More information available here: // https://www.kernel.org/doc/Documentation/sysctl/vm.txt func (fs FS) Zoneinfo() ([]Zoneinfo, error) { - data, err := ioutil.ReadFile(fs.proc.Path("zoneinfo")) + data, err := os.ReadFile(fs.proc.Path("zoneinfo")) if err != nil { return nil, fmt.Errorf("error reading zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err) } diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go deleted file mode 100644 index cf66309c4..000000000 --- a/vendor/golang.org/x/net/context/context.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package context defines the Context type, which carries deadlines, -// cancelation signals, and other request-scoped values across API boundaries -// and between processes. -// As of Go 1.7 this package is available in the standard library under the -// name context. https://golang.org/pkg/context. -// -// Incoming requests to a server should create a Context, and outgoing calls to -// servers should accept a Context. The chain of function calls between must -// propagate the Context, optionally replacing it with a modified copy created -// using WithDeadline, WithTimeout, WithCancel, or WithValue. -// -// Programs that use Contexts should follow these rules to keep interfaces -// consistent across packages and enable static analysis tools to check context -// propagation: -// -// Do not store Contexts inside a struct type; instead, pass a Context -// explicitly to each function that needs it. The Context should be the first -// parameter, typically named ctx: -// -// func DoSomething(ctx context.Context, arg Arg) error { -// // ... use ctx ... -// } -// -// Do not pass a nil Context, even if a function permits it. Pass context.TODO -// if you are unsure about which Context to use. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -// -// The same Context may be passed to functions running in different goroutines; -// Contexts are safe for simultaneous use by multiple goroutines. -// -// See http://blog.golang.org/context for example code for a server that uses -// Contexts. -package context // import "golang.org/x/net/context" - -// Background returns a non-nil, empty Context. It is never canceled, has no -// values, and has no deadline. It is typically used by the main function, -// initialization, and tests, and as the top-level Context for incoming -// requests. -func Background() Context { - return background -} - -// TODO returns a non-nil, empty Context. Code should use context.TODO when -// it's unclear which Context to use or it is not yet available (because the -// surrounding function has not yet been extended to accept a Context -// parameter). TODO is recognized by static analysis tools that determine -// whether Contexts are propagated correctly in a program. -func TODO() Context { - return todo -} diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go deleted file mode 100644 index 2cb9c408f..000000000 --- a/vendor/golang.org/x/net/context/go17.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.7 -// +build go1.7 - -package context - -import ( - "context" // standard library's context, as of Go 1.7 - "time" -) - -var ( - todo = context.TODO() - background = context.Background() -) - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = context.Canceled - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = context.DeadlineExceeded - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - ctx, f := context.WithCancel(parent) - return ctx, f -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - ctx, f := context.WithDeadline(parent, deadline) - return ctx, f -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return context.WithValue(parent, key, val) -} diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go deleted file mode 100644 index 64d31ecc3..000000000 --- a/vendor/golang.org/x/net/context/go19.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.9 -// +build go1.9 - -package context - -import "context" // standard library's context, as of Go 1.7 - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context = context.Context - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc = context.CancelFunc diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go deleted file mode 100644 index 7b6b68511..000000000 --- a/vendor/golang.org/x/net/context/pre_go17.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.7 -// +build !go1.7 - -package context - -import ( - "errors" - "fmt" - "sync" - "time" -) - -// An emptyCtx is never canceled, has no values, and has no deadline. It is not -// struct{}, since vars of this type must have distinct addresses. -type emptyCtx int - -func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { - return -} - -func (*emptyCtx) Done() <-chan struct{} { - return nil -} - -func (*emptyCtx) Err() error { - return nil -} - -func (*emptyCtx) Value(key interface{}) interface{} { - return nil -} - -func (e *emptyCtx) String() string { - switch e { - case background: - return "context.Background" - case todo: - return "context.TODO" - } - return "unknown empty Context" -} - -var ( - background = new(emptyCtx) - todo = new(emptyCtx) -) - -// Canceled is the error returned by Context.Err when the context is canceled. -var Canceled = errors.New("context canceled") - -// DeadlineExceeded is the error returned by Context.Err when the context's -// deadline passes. -var DeadlineExceeded = errors.New("context deadline exceeded") - -// WithCancel returns a copy of parent with a new Done channel. The returned -// context's Done channel is closed when the returned cancel function is called -// or when the parent context's Done channel is closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { - c := newCancelCtx(parent) - propagateCancel(parent, c) - return c, func() { c.cancel(true, Canceled) } -} - -// newCancelCtx returns an initialized cancelCtx. -func newCancelCtx(parent Context) *cancelCtx { - return &cancelCtx{ - Context: parent, - done: make(chan struct{}), - } -} - -// propagateCancel arranges for child to be canceled when parent is. -func propagateCancel(parent Context, child canceler) { - if parent.Done() == nil { - return // parent is never canceled - } - if p, ok := parentCancelCtx(parent); ok { - p.mu.Lock() - if p.err != nil { - // parent has already been canceled - child.cancel(false, p.err) - } else { - if p.children == nil { - p.children = make(map[canceler]bool) - } - p.children[child] = true - } - p.mu.Unlock() - } else { - go func() { - select { - case <-parent.Done(): - child.cancel(false, parent.Err()) - case <-child.Done(): - } - }() - } -} - -// parentCancelCtx follows a chain of parent references until it finds a -// *cancelCtx. This function understands how each of the concrete types in this -// package represents its parent. -func parentCancelCtx(parent Context) (*cancelCtx, bool) { - for { - switch c := parent.(type) { - case *cancelCtx: - return c, true - case *timerCtx: - return c.cancelCtx, true - case *valueCtx: - parent = c.Context - default: - return nil, false - } - } -} - -// removeChild removes a context from its parent. -func removeChild(parent Context, child canceler) { - p, ok := parentCancelCtx(parent) - if !ok { - return - } - p.mu.Lock() - if p.children != nil { - delete(p.children, child) - } - p.mu.Unlock() -} - -// A canceler is a context type that can be canceled directly. The -// implementations are *cancelCtx and *timerCtx. -type canceler interface { - cancel(removeFromParent bool, err error) - Done() <-chan struct{} -} - -// A cancelCtx can be canceled. When canceled, it also cancels any children -// that implement canceler. -type cancelCtx struct { - Context - - done chan struct{} // closed by the first cancel call. - - mu sync.Mutex - children map[canceler]bool // set to nil by the first cancel call - err error // set to non-nil by the first cancel call -} - -func (c *cancelCtx) Done() <-chan struct{} { - return c.done -} - -func (c *cancelCtx) Err() error { - c.mu.Lock() - defer c.mu.Unlock() - return c.err -} - -func (c *cancelCtx) String() string { - return fmt.Sprintf("%v.WithCancel", c.Context) -} - -// cancel closes c.done, cancels each of c's children, and, if -// removeFromParent is true, removes c from its parent's children. -func (c *cancelCtx) cancel(removeFromParent bool, err error) { - if err == nil { - panic("context: internal error: missing cancel error") - } - c.mu.Lock() - if c.err != nil { - c.mu.Unlock() - return // already canceled - } - c.err = err - close(c.done) - for child := range c.children { - // NOTE: acquiring the child's lock while holding parent's lock. - child.cancel(false, err) - } - c.children = nil - c.mu.Unlock() - - if removeFromParent { - removeChild(c.Context, c) - } -} - -// WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned -// context's Done channel is closed when the deadline expires, when the returned -// cancel function is called, or when the parent context's Done channel is -// closed, whichever happens first. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { - if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { - // The current deadline is already sooner than the new one. - return WithCancel(parent) - } - c := &timerCtx{ - cancelCtx: newCancelCtx(parent), - deadline: deadline, - } - propagateCancel(parent, c) - d := deadline.Sub(time.Now()) - if d <= 0 { - c.cancel(true, DeadlineExceeded) // deadline has already passed - return c, func() { c.cancel(true, Canceled) } - } - c.mu.Lock() - defer c.mu.Unlock() - if c.err == nil { - c.timer = time.AfterFunc(d, func() { - c.cancel(true, DeadlineExceeded) - }) - } - return c, func() { c.cancel(true, Canceled) } -} - -// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to -// implement Done and Err. It implements cancel by stopping its timer then -// delegating to cancelCtx.cancel. -type timerCtx struct { - *cancelCtx - timer *time.Timer // Under cancelCtx.mu. - - deadline time.Time -} - -func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { - return c.deadline, true -} - -func (c *timerCtx) String() string { - return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) -} - -func (c *timerCtx) cancel(removeFromParent bool, err error) { - c.cancelCtx.cancel(false, err) - if removeFromParent { - // Remove this timerCtx from its parent cancelCtx's children. - removeChild(c.cancelCtx.Context, c) - } - c.mu.Lock() - if c.timer != nil { - c.timer.Stop() - c.timer = nil - } - c.mu.Unlock() -} - -// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete: -// -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } -func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { - return WithDeadline(parent, time.Now().Add(timeout)) -} - -// WithValue returns a copy of parent in which the value associated with key is -// val. -// -// Use context Values only for request-scoped data that transits processes and -// APIs, not for passing optional parameters to functions. -func WithValue(parent Context, key interface{}, val interface{}) Context { - return &valueCtx{parent, key, val} -} - -// A valueCtx carries a key-value pair. It implements Value for that key and -// delegates all other calls to the embedded Context. -type valueCtx struct { - Context - key, val interface{} -} - -func (c *valueCtx) String() string { - return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) -} - -func (c *valueCtx) Value(key interface{}) interface{} { - if c.key == key { - return c.val - } - return c.Context.Value(key) -} diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go deleted file mode 100644 index 1f9715341..000000000 --- a/vendor/golang.org/x/net/context/pre_go19.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.9 -// +build !go1.9 - -package context - -import "time" - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - // - // WithCancel arranges for Done to be closed when cancel is called; - // WithDeadline arranges for Done to be closed when the deadline - // expires; WithTimeout arranges for Done to be closed when the timeout - // elapses. - // - // Done is provided for use in select statements: - // - // // Stream generates values with DoSomething and sends them to out - // // until DoSomething returns an error or ctx.Done is closed. - // func Stream(ctx context.Context, out chan<- Value) error { - // for { - // v, err := DoSomething(ctx) - // if err != nil { - // return err - // } - // select { - // case <-ctx.Done(): - // return ctx.Err() - // case out <- v: - // } - // } - // } - // - // See http://blog.golang.org/pipelines for more examples of how to use - // a Done channel for cancelation. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - // - // A key identifies a specific value in a Context. Functions that wish - // to store values in Context typically allocate a key in a global - // variable then use that key as the argument to context.WithValue and - // Context.Value. A key can be any type that supports equality; - // packages should define keys as an unexported type to avoid - // collisions. - // - // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: - // - // // Package user defines a User type that's stored in Contexts. - // package user - // - // import "golang.org/x/net/context" - // - // // User is the type of value stored in the Contexts. - // type User struct {...} - // - // // key is an unexported type for keys defined in this package. - // // This prevents collisions with keys defined in other packages. - // type key int - // - // // userKey is the key for user.User values in Contexts. It is - // // unexported; clients use user.NewContext and user.FromContext - // // instead of using this key directly. - // var userKey key = 0 - // - // // NewContext returns a new Context that carries value u. - // func NewContext(ctx context.Context, u *User) context.Context { - // return context.WithValue(ctx, userKey, u) - // } - // - // // FromContext returns the User value stored in ctx, if any. - // func FromContext(ctx context.Context) (*User, bool) { - // u, ok := ctx.Value(userKey).(*User) - // return u, ok - // } - Value(key interface{}) interface{} -} - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc func() diff --git a/vendor/modules.txt b/vendor/modules.txt index ae6ce1069..e9cf93347 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -329,9 +329,12 @@ github.com/grpc-ecosystem/go-grpc-middleware/tags github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing github.com/grpc-ecosystem/go-grpc-middleware/util/backoffutils github.com/grpc-ecosystem/go-grpc-middleware/util/metautils -# github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 -## explicit -github.com/grpc-ecosystem/go-grpc-prometheus +# github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 +## explicit; go 1.19 +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus +# github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 +## explicit; go 1.14 +github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors # github.com/hashicorp/errwrap v1.0.0 ## explicit github.com/hashicorp/errwrap @@ -549,22 +552,22 @@ github.com/pmezard/go-difflib/difflib # github.com/polyfloyd/go-errorlint v1.1.0 ## explicit; go 1.13 github.com/polyfloyd/go-errorlint/errorlint -# github.com/prometheus/client_golang v1.12.1 -## explicit; go 1.13 +# github.com/prometheus/client_golang v1.14.0 +## explicit; go 1.17 github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp github.com/prometheus/client_golang/prometheus/testutil/promlint -# github.com/prometheus/client_model v0.2.0 +# github.com/prometheus/client_model v0.3.0 ## explicit; go 1.9 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.32.1 -## explicit; go 1.13 +# github.com/prometheus/common v0.37.0 +## explicit; go 1.16 github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model -# github.com/prometheus/procfs v0.7.3 -## explicit; go 1.13 +# github.com/prometheus/procfs v0.8.0 +## explicit; go 1.17 github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util @@ -810,7 +813,6 @@ golang.org/x/mod/module golang.org/x/mod/semver # golang.org/x/net v0.17.0 ## explicit; go 1.17 -golang.org/x/net/context golang.org/x/net/http/httpguts golang.org/x/net/http2 golang.org/x/net/http2/hpack From bd51332b3980ae678c9c8dcd50a78c107f4ada91 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:27:54 +0200 Subject: [PATCH 14/31] Use github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus --- grpc/client.go | 9 ++++++--- grpc/server.go | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/grpc/client.go b/grpc/client.go index 513554a3b..020d313aa 100644 --- a/grpc/client.go +++ b/grpc/client.go @@ -15,9 +15,9 @@ import ( "github.com/pace/bricks/locale" "github.com/pace/bricks/maintenance/log" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" ) func DialContext(ctx context.Context, addr string) (*grpc.ClientConn, error) { @@ -30,13 +30,16 @@ func Dial(addr string) (*grpc.ClientConn, error) { func dialCtx(ctx context.Context, addr string) (*grpc.ClientConn, error) { var conn *grpc.ClientConn + + clientMetrics := grpc_prometheus.NewClientMetrics() + opts := []grpc_retry.CallOption{ grpc_retry.WithBackoff(grpc_retry.BackoffLinear(100 * time.Millisecond)), } conn, err := grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithChainStreamInterceptor( grpc_opentracing.StreamClientInterceptor(), - grpc_prometheus.StreamClientInterceptor, + grpc_opentracing.StreamClientInterceptor(), grpc_retry.StreamClientInterceptor(opts...), func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { start := time.Now() @@ -51,7 +54,7 @@ func dialCtx(ctx context.Context, addr string) (*grpc.ClientConn, error) { ), grpc.WithChainUnaryInterceptor( grpc_opentracing.UnaryClientInterceptor(), - grpc_prometheus.UnaryClientInterceptor, + clientMetrics.UnaryClientInterceptor(), grpc_retry.UnaryClientInterceptor(opts...), func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { start := time.Now() diff --git a/grpc/server.go b/grpc/server.go index 34f30fab1..d1858dc57 100644 --- a/grpc/server.go +++ b/grpc/server.go @@ -12,9 +12,9 @@ import ( grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags" grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" - grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/pace/bricks/http/security" "github.com/pace/bricks/locale" "github.com/pace/bricks/maintenance/errors" @@ -69,11 +69,13 @@ func Listener() (net.Listener, error) { } func Server(ab AuthBackend) *grpc.Server { + serverMetrics := grpc_prometheus.NewServerMetrics() + myServer := grpc.NewServer( grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( grpc_ctxtags.StreamServerInterceptor(), grpc_opentracing.StreamServerInterceptor(), - grpc_prometheus.StreamServerInterceptor, + serverMetrics.StreamServerInterceptor(), func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { ctx := stream.Context() ctx, md := prepareContext(ctx) @@ -109,7 +111,7 @@ func Server(ab AuthBackend) *grpc.Server { grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer( grpc_ctxtags.UnaryServerInterceptor(), grpc_opentracing.UnaryServerInterceptor(), - grpc_prometheus.UnaryServerInterceptor, + serverMetrics.UnaryServerInterceptor(), func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { ctx, md := prepareContext(ctx) From 4155797bf632d4907e64b03e43d0bf055c266d6e Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:29:12 +0200 Subject: [PATCH 15/31] gomod: Update github.com/mattn/go-isatty --- go.mod | 2 +- go.sum | 5 +++-- vendor/github.com/mattn/go-isatty/isatty_bsd.go | 3 ++- vendor/github.com/mattn/go-isatty/isatty_others.go | 5 +++-- vendor/github.com/mattn/go-isatty/isatty_tcgets.go | 3 ++- vendor/modules.txt | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 706ce7b99..20a0dad76 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 github.com/jpillora/backoff v1.0.0 - github.com/mattn/go-isatty v0.0.17 + github.com/mattn/go-isatty v0.0.20 github.com/mattn/goveralls v0.0.9 github.com/minio/minio-go/v7 v7.0.7 github.com/opentracing/opentracing-go v1.1.0 diff --git a/go.sum b/go.sum index e510bbbb9..ba7d54607 100644 --- a/go.sum +++ b/go.sum @@ -443,8 +443,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -911,6 +911,7 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index d569c0c94..d0ea68f40 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -1,6 +1,7 @@ -//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine +//go:build (darwin || freebsd || openbsd || netbsd || dragonfly || hurd) && !appengine && !tinygo // +build darwin freebsd openbsd netbsd dragonfly hurd // +build !appengine +// +build !tinygo package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go index 31503226f..7402e0618 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_others.go +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -1,5 +1,6 @@ -//go:build appengine || js || nacl || wasm -// +build appengine js nacl wasm +//go:build (appengine || js || nacl || tinygo || wasm) && !windows +// +build appengine js nacl tinygo wasm +// +build !windows package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go index 67787657f..0337d8cf6 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go +++ b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go @@ -1,6 +1,7 @@ -//go:build (linux || aix || zos) && !appengine +//go:build (linux || aix || zos) && !appengine && !tinygo // +build linux aix zos // +build !appengine +// +build !tinygo package isatty diff --git a/vendor/modules.txt b/vendor/modules.txt index e9cf93347..710f240eb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -442,7 +442,7 @@ github.com/matoous/godox # github.com/mattn/go-colorable v0.1.13 ## explicit; go 1.15 github.com/mattn/go-colorable -# github.com/mattn/go-isatty v0.0.17 +# github.com/mattn/go-isatty v0.0.20 ## explicit; go 1.15 github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.9 From 196d80d8fb4b3008e07341fe2967be6570cd7154 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:29:48 +0200 Subject: [PATCH 16/31] gomod: Update github.com/mattn/goveralls --- go.mod | 6 +- go.sum | 22 +- vendor/github.com/mattn/goveralls/LICENSE | 21 + vendor/github.com/mattn/goveralls/README.md | 83 +--- vendor/github.com/mattn/goveralls/gocover.go | 10 + .../mattn/goveralls/gocover_ge1.8.go | 19 - .../mattn/goveralls/gocover_lt1.8.go | 7 - .../github.com/mattn/goveralls/goveralls.go | 43 +- .../x/tools/go/analysis/analysis.go | 8 +- .../x/tools/go/analysis/diagnostic.go | 11 + .../go/analysis/passes/asmdecl/asmdecl.go | 1 + .../tools/go/analysis/passes/assign/assign.go | 12 +- .../x/tools/go/analysis/passes/assign/doc.go | 14 + .../tools/go/analysis/passes/atomic/atomic.go | 15 +- .../x/tools/go/analysis/passes/atomic/doc.go | 17 + .../passes/atomicalign/atomicalign.go | 1 + .../x/tools/go/analysis/passes/bools/bools.go | 1 + .../go/analysis/passes/buildssa/buildssa.go | 1 + .../go/analysis/passes/buildtag/buildtag.go | 1 + .../go/analysis/passes/cgocall/cgocall.go | 1 + .../go/analysis/passes/composite/composite.go | 1 + .../go/analysis/passes/copylock/copylock.go | 1 + .../go/analysis/passes/ctrlflow/ctrlflow.go | 1 + .../passes/deepequalerrors/deepequalerrors.go | 1 + .../go/analysis/passes/errorsas/errorsas.go | 1 + .../passes/fieldalignment/fieldalignment.go | 1 + .../go/analysis/passes/findcall/findcall.go | 1 + .../passes/framepointer/framepointer.go | 1 + .../passes/httpresponse/httpresponse.go | 1 + .../go/analysis/passes/ifaceassert/doc.go | 24 ++ .../passes/ifaceassert/ifaceassert.go | 24 +- .../go/analysis/passes/inspect/inspect.go | 1 + .../internal/analysisutil/extractdoc.go | 113 +++++ .../go/analysis/passes/loopclosure/doc.go | 68 +++ .../passes/loopclosure/loopclosure.go | 67 +-- .../go/analysis/passes/lostcancel/doc.go | 16 + .../analysis/passes/lostcancel/lostcancel.go | 15 +- .../x/tools/go/analysis/passes/nilfunc/doc.go | 13 + .../go/analysis/passes/nilfunc/nilfunc.go | 8 +- .../x/tools/go/analysis/passes/nilness/doc.go | 45 ++ .../go/analysis/passes/nilness/nilness.go | 45 +- .../go/analysis/passes/pkgfact/pkgfact.go | 1 + .../x/tools/go/analysis/passes/printf/doc.go | 47 +++ .../tools/go/analysis/passes/printf/printf.go | 42 +- .../passes/reflectvaluecompare/doc.go | 27 ++ .../reflectvaluecompare.go | 27 +- .../x/tools/go/analysis/passes/shadow/doc.go | 33 ++ .../tools/go/analysis/passes/shadow/shadow.go | 33 +- .../x/tools/go/analysis/passes/shift/shift.go | 1 + .../go/analysis/passes/sigchanyzer/doc.go | 17 + .../passes/sigchanyzer/sigchanyzer.go | 11 +- .../go/analysis/passes/sortslice/analyzer.go | 2 + .../go/analysis/passes/stdmethods/doc.go | 30 ++ .../analysis/passes/stdmethods/stdmethods.go | 29 +- .../go/analysis/passes/stringintconv/doc.go | 21 + .../analysis/passes/stringintconv/string.go | 21 +- .../go/analysis/passes/structtag/structtag.go | 1 + .../analysis/passes/testinggoroutine/doc.go | 22 + .../testinggoroutine/testinggoroutine.go | 19 +- .../x/tools/go/analysis/passes/tests/doc.go | 18 + .../x/tools/go/analysis/passes/tests/tests.go | 22 +- .../go/analysis/passes/timeformat/doc.go | 15 + .../analysis/passes/timeformat/timeformat.go | 8 +- .../tools/go/analysis/passes/unmarshal/doc.go | 14 + .../go/analysis/passes/unmarshal/unmarshal.go | 13 +- .../go/analysis/passes/unreachable/doc.go | 14 + .../passes/unreachable/unreachable.go | 13 +- .../tools/go/analysis/passes/unsafeptr/doc.go | 17 + .../go/analysis/passes/unsafeptr/unsafeptr.go | 7 +- .../go/analysis/passes/unusedresult/doc.go | 17 + .../passes/unusedresult/unusedresult.go | 34 +- .../go/analysis/passes/unusedwrite/doc.go | 34 ++ .../passes/unusedwrite/unusedwrite.go | 33 +- .../internal/analysisinternal/analysis.go | 390 ------------------ .../x/tools/internal/gcimporter/iexport.go | 8 +- .../x/tools/internal/gcimporter/iimport.go | 34 +- .../internal/tokeninternal/tokeninternal.go | 92 +++++ vendor/modules.txt | 9 +- 78 files changed, 1053 insertions(+), 865 deletions(-) create mode 100644 vendor/github.com/mattn/goveralls/LICENSE delete mode 100644 vendor/github.com/mattn/goveralls/gocover_ge1.8.go delete mode 100644 vendor/github.com/mattn/goveralls/gocover_lt1.8.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/assign/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/atomic/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/lostcancel/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/nilfunc/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/nilness/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/printf/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/shadow/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/stdmethods/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/stringintconv/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/tests/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/timeformat/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/unmarshal/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/doc.go delete mode 100644 vendor/golang.org/x/tools/internal/analysisinternal/analysis.go diff --git a/go.mod b/go.mod index 20a0dad76..af873ea1d 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 github.com/jpillora/backoff v1.0.0 github.com/mattn/go-isatty v0.0.20 - github.com/mattn/goveralls v0.0.9 + github.com/mattn/goveralls v0.0.12 github.com/minio/minio-go/v7 v7.0.7 github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.9.1 @@ -212,11 +212,11 @@ require ( golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 // indirect - golang.org/x/mod v0.9.0 // indirect + golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.15.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/tools v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index ba7d54607..bd0166110 100644 --- a/go.sum +++ b/go.sum @@ -448,8 +448,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/goveralls v0.0.9 h1:XmIwwrO9a9pqSW6IpI89BSCShzQxx0j/oKnnvELQNME= -github.com/mattn/goveralls v0.0.9/go.mod h1:FRbM1PS8oVsOe9JtdzAAXM+DsvDMMHcM1C7drGJD8HY= +github.com/mattn/goveralls v0.0.12 h1:PEEeF0k1SsTjOBQ8FOmrOAoCu4ytuMaWCnWe94zxbCg= +github.com/mattn/goveralls v0.0.12/go.mod h1:44ImGEUfmqH8bBtaMrYKsM65LXfNLWmwaxFGjZwgMSQ= 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/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= @@ -765,8 +765,9 @@ golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -815,6 +816,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -911,7 +914,9 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -920,6 +925,8 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= 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= @@ -931,6 +938,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1015,8 +1024,9 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA= golang.org/x/tools/cmd/cover v0.1.0-deprecated/go.mod h1:hMDiIvlpN1NoVgmjLjUJE9tMHyxHjFX7RuQ+rW12mSA= golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e h1:5Hq/b1GYIt4/LvB6c4KOX+XyV1iOEjrP8uigwK7EQpU= diff --git a/vendor/github.com/mattn/goveralls/LICENSE b/vendor/github.com/mattn/goveralls/LICENSE new file mode 100644 index 000000000..a6523a00c --- /dev/null +++ b/vendor/github.com/mattn/goveralls/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Yasuhiro Matsumoto + +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. diff --git a/vendor/github.com/mattn/goveralls/README.md b/vendor/github.com/mattn/goveralls/README.md index 510901a45..20c480bab 100644 --- a/vendor/github.com/mattn/goveralls/README.md +++ b/vendor/github.com/mattn/goveralls/README.md @@ -6,10 +6,10 @@ continuous code coverage tracking system. # Installation -`goveralls` requires a working Go installation (Go-1.2 or higher). +`goveralls` requires a working Go installation (Go-1.13 or higher). ```bash -$ go get github.com/mattn/goveralls +$ go install github.com/mattn/goveralls@latest ``` @@ -38,7 +38,7 @@ docs](https://docs.coveralls.io/parallel-build-webhook) for more details). There is no need to run `go test` separately, as `goveralls` runs the entire test suite. -## Github Actions +## GitHub Actions [shogo82148/actions-goveralls](https://github.com/marketplace/actions/actions-goveralls) is available on GitHub Marketplace. It provides the shorthand of the GitHub Actions YAML configure. @@ -52,9 +52,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Set up Go - uses: actions/setup-go@v1 + uses: actions/setup-go@v2 with: - go-version: '1.13' + go-version: '1.16' - name: Check out code uses: actions/checkout@v2 - name: Install dependencies @@ -64,9 +64,7 @@ jobs: run: | go test -race -covermode atomic -coverprofile=covprofile ./... - name: Install goveralls - env: - GO111MODULE: off - run: go get github.com/mattn/goveralls + run: go install github.com/mattn/goveralls@latest - name: Send coverage env: COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -78,79 +76,34 @@ jobs: # path-to-profile: covprofile ``` -### Test with Legacy GOPATH mode - -If you want to use Go 1.10 or earlier, you have to set `GOPATH` environment value and the working directory. -See for more detail. - -Here is an example for testing `example.com/owner/repo` package. - -```yaml -name: Quality -on: [push, pull_request] -jobs: - test: - name: Test with Coverage - runs-on: ubuntu-latest - steps: - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: '1.10' - - # add this step - - name: Set up GOPATH - run: | - echo "GOPATH=${{ github.workspace }}" >> "$GITHUB_ENV" - echo "${{ github.workspace }}/bin" >> "$GITHUB_PATH" - - - name: Check out code - uses: actions/checkout@v2 - with: - path: src/example.com/owner/repo # add this - - name: Run Unit tests - run: | - go test -race -covermode atomic -coverprofile=covprofile ./... - working-directory: src/example.com/owner/repo # add this - - name: Install goveralls - env: - GO111MODULE: off - run: go get github.com/mattn/goveralls - - name: Send coverage - env: - COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: goveralls -coverprofile=covprofile -service=github - working-directory: src/example.com/owner/repo # add this -``` - ## Travis CI ### GitHub Integration -Enable Travis-CI on your github repository settings. +Enable Travis-CI on your GitHub repository settings. -For a **public** github repository put bellow's `.travis.yml`. +For a **public** GitHub repository put bellow's `.travis.yml`. ```yml language: go go: - tip before_install: - - go get github.com/mattn/goveralls + - go install github.com/mattn/goveralls@latest script: - $GOPATH/bin/goveralls -service=travis-ci ``` -For a **public** github repository, it is not necessary to define your repository key (`COVERALLS_TOKEN`). +For a **public** GitHub repository, it is not necessary to define your repository key (`COVERALLS_TOKEN`). -For a **private** github repository put bellow's `.travis.yml`. If you use **travis pro**, you need to specify `-service=travis-pro` instead of `-service=travis-ci`. +For a **private** GitHub repository put bellow's `.travis.yml`. If you use **travis pro**, you need to specify `-service=travis-pro` instead of `-service=travis-ci`. ```yml language: go go: - tip before_install: - - go get github.com/mattn/goveralls + - go install github.com/mattn/goveralls@latest script: - $GOPATH/bin/goveralls -service=travis-pro ``` @@ -179,7 +132,7 @@ env: ### For others: ``` -$ go get github.com/mattn/goveralls +$ go install github.com/mattn/goveralls@latest $ go test -covermode=count -coverprofile=profile.cov $ goveralls -coverprofile=profile.cov -service=travis-ci ``` @@ -195,7 +148,7 @@ COVERALLS_TOKEN=your_token_goes_here Replace the `go test` line in your `Commands` with these lines: ``` -$ go get github.com/mattn/goveralls +$ go install github.com/mattn/goveralls@latest $ goveralls -service drone.io ``` @@ -217,7 +170,7 @@ In your `circle.yml` add the following commands under the `test` section. ```yml test: pre: - - go get github.com/mattn/goveralls + - go install github.com/mattn/goveralls@latest override: - go test -v -cover -race -coverprofile=/home/ubuntu/coverage.out post: @@ -239,7 +192,7 @@ More instructions on how to do this can be found in the [Semaphore documentation Replace the `go test` line in your `Commands` with these lines: ``` -$ go get github.com/mattn/goveralls +$ go install github.com/mattn/goveralls@latest $ goveralls -service semaphore ``` @@ -293,7 +246,7 @@ COVERALLS_TOKEN=your_token_goes_here Setup build steps: ``` -$ go get github.com/mattn/goveralls +$ go install github.com/mattn/goveralls@latest $ export PULL_REQUEST_NUMBER=%teamcity.build.branch% $ goveralls -service teamcity -jobid %teamcity.build.id% -jobnumber %build.number% ``` @@ -320,7 +273,7 @@ test: when: always script: - go test -covermode atomic -coverprofile=coverage.txt ./... - - go get github.com/mattn/goveralls + - go install github.com/mattn/goveralls@latest - goveralls -service=gitlab -coverprofile=coverage.txt ``` diff --git a/vendor/github.com/mattn/goveralls/gocover.go b/vendor/github.com/mattn/goveralls/gocover.go index ecd1b5d68..1c6fdfa84 100644 --- a/vendor/github.com/mattn/goveralls/gocover.go +++ b/vendor/github.com/mattn/goveralls/gocover.go @@ -16,6 +16,7 @@ import ( "path/filepath" "strings" + "golang.org/x/mod/modfile" "golang.org/x/tools/cover" ) @@ -176,3 +177,12 @@ func parseCover(fn string) ([]*SourceFile, error) { return sourceFiles, nil } + +func findRootPackage(rootDirectory string) string { + modPath := filepath.Join(rootDirectory, "go.mod") + content, err := ioutil.ReadFile(modPath) + if err != nil { + return "" + } + return modfile.ModulePath(content) +} diff --git a/vendor/github.com/mattn/goveralls/gocover_ge1.8.go b/vendor/github.com/mattn/goveralls/gocover_ge1.8.go deleted file mode 100644 index 4b880a56f..000000000 --- a/vendor/github.com/mattn/goveralls/gocover_ge1.8.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build go1.8 - -package main - -import ( - "io/ioutil" - "path/filepath" - - "golang.org/x/mod/modfile" -) - -func findRootPackage(rootDirectory string) string { - modPath := filepath.Join(rootDirectory, "go.mod") - content, err := ioutil.ReadFile(modPath) - if err != nil { - return "" - } - return modfile.ModulePath(content) -} diff --git a/vendor/github.com/mattn/goveralls/gocover_lt1.8.go b/vendor/github.com/mattn/goveralls/gocover_lt1.8.go deleted file mode 100644 index 263306e39..000000000 --- a/vendor/github.com/mattn/goveralls/gocover_lt1.8.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !go1.8 - -package main - -func findRootPackage(rootDirectory string) string { - return "" -} diff --git a/vendor/github.com/mattn/goveralls/goveralls.go b/vendor/github.com/mattn/goveralls/goveralls.go index 126feb7d5..fa8c24c2a 100644 --- a/vendor/github.com/mattn/goveralls/goveralls.go +++ b/vendor/github.com/mattn/goveralls/goveralls.go @@ -248,7 +248,9 @@ func processParallelFinish(jobID, token string) error { params := make(url.Values) params.Set("repo_token", token) - params.Set("repo_name", name) + if name != "" { + params.Set("repo_name", name) + } params.Set("payload[build_num]", jobID) params.Set("payload[status]", "done") res, err := http.PostForm(*endpoint+"/webhook", params) @@ -268,12 +270,23 @@ func processParallelFinish(jobID, token string) error { return fmt.Errorf("unable to read response body from coveralls: %s", err) } - if res.StatusCode >= http.StatusInternalServerError && *shallow { - fmt.Println("coveralls server failed internally") - return nil + if *shallow { + if res.StatusCode >= http.StatusInternalServerError { + fmt.Println("coveralls server failed internally") + return nil + } + + // XXX: It looks that Coveralls is under maintenance. + // Coveralls serves the maintenance page as a static HTML hosting, + // and the maintenance page doesn't accept POST method. + // See https://github.com/mattn/goveralls/issues/204 + if res.StatusCode == http.StatusMethodNotAllowed { + fmt.Println("it looks that Coveralls is under maintenance. visit https://status.coveralls.io/") + return nil + } } - if res.StatusCode != 200 { + if res.StatusCode != http.StatusOK { return fmt.Errorf("bad response status from coveralls: %d\n%s", res.StatusCode, bodyBytes) } @@ -379,6 +392,9 @@ func process() error { if prNumber := os.Getenv("CIRCLE_PR_NUMBER"); prNumber != "" { // for Circle CI (pull request from forked repo) pullRequest = prNumber + } else if prURL := os.Getenv("CIRCLE_PULL_REQUEST"); prURL != "" { + // for Circle CI (all other pull requests) + pullRequest = regexp.MustCompile(`[0-9]+$`).FindString(prURL) } else if prNumber := os.Getenv("TRAVIS_PULL_REQUEST"); prNumber != "" && prNumber != "false" { pullRequest = prNumber } else if prNumber := os.Getenv("APPVEYOR_PULL_REQUEST_NUMBER"); prNumber != "" { @@ -502,9 +518,20 @@ func process() error { return fmt.Errorf("unable to read response body from coveralls: %s", err) } - if res.StatusCode >= http.StatusInternalServerError && *shallow { - fmt.Println("coveralls server failed internally") - return nil + if *shallow { + if res.StatusCode >= http.StatusInternalServerError { + fmt.Println("coveralls server failed internally") + return nil + } + + // XXX: It looks that Coveralls is under maintenance. + // Coveralls serves the maintenance page as a static HTML hosting, + // and the maintenance page doesn't accept POST method. + // See https://github.com/mattn/goveralls/issues/204 + if res.StatusCode == http.StatusMethodNotAllowed { + fmt.Println("it looks that Coveralls is under maintenance. visit https://status.coveralls.io/") + return nil + } } if res.StatusCode != 200 { diff --git a/vendor/golang.org/x/tools/go/analysis/analysis.go b/vendor/golang.org/x/tools/go/analysis/analysis.go index 44ada22a0..e51e58b3d 100644 --- a/vendor/golang.org/x/tools/go/analysis/analysis.go +++ b/vendor/golang.org/x/tools/go/analysis/analysis.go @@ -24,6 +24,10 @@ type Analyzer struct { // (no capital or period, max ~60 letters). Doc string + // URL holds an optional link to a web page with additional + // documentation for this analyzer. + URL string + // Flags defines any flags accepted by the analyzer. // The manner in which these flags are exposed to the user // depends on the driver which runs the analyzer. @@ -145,11 +149,7 @@ type Pass struct { // WARNING: This is an experimental API and may change in the future. AllObjectFacts func() []ObjectFact - // typeErrors contains types.Errors that are associated with the pkg. - typeErrors []types.Error - /* Further fields may be added in future. */ - // For example, suggested or applied refactorings. } // PackageFact is a package together with an associated fact. diff --git a/vendor/golang.org/x/tools/go/analysis/diagnostic.go b/vendor/golang.org/x/tools/go/analysis/diagnostic.go index 5cdcf46d2..7646ad0d4 100644 --- a/vendor/golang.org/x/tools/go/analysis/diagnostic.go +++ b/vendor/golang.org/x/tools/go/analysis/diagnostic.go @@ -20,6 +20,17 @@ type Diagnostic struct { Category string // optional Message string + // URL is the optional location of a web page that provides + // additional documentation for this diagnostic. + // + // If URL is empty but a Category is specified, then the + // Analysis driver should treat the URL as "#"+Category. + // + // The URL may be relative. If so, the base URL is that of the + // Analyzer that produced the diagnostic; + // see https://pkg.go.dev/net/url#URL.ResolveReference. + URL string + // SuggestedFixes contains suggested fixes for a diagnostic which can be used to perform // edits to a file that address the diagnostic. // TODO(matloob): Should multiple SuggestedFixes be allowed for a diagnostic? diff --git a/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go index 7288559fc..e24dac986 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go @@ -27,6 +27,7 @@ const Doc = "report mismatches between assembly files and Go declarations" var Analyzer = &analysis.Analyzer{ Name: "asmdecl", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/asmdecl", Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go index 89146b733..10489bea1 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package assign defines an Analyzer that detects useless assignments. package assign // TODO(adonovan): check also for assignments to struct fields inside // methods that are on T instead of *T. import ( + _ "embed" "fmt" "go/ast" "go/token" @@ -21,15 +21,13 @@ import ( "golang.org/x/tools/go/ast/inspector" ) -const Doc = `check for useless assignments - -This checker reports assignments of the form x = x or a[i] = a[i]. -These are almost always useless, and even when they aren't they are -usually a mistake.` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "assign", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "assign"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/assign/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/assign/doc.go new file mode 100644 index 000000000..a4b1b64c5 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/assign/doc.go @@ -0,0 +1,14 @@ +// Copyright 2023 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 assign defines an Analyzer that detects useless assignments. +// +// # Analyzer assign +// +// assign: check for useless assignments +// +// This checker reports assignments of the form x = x or a[i] = a[i]. +// These are almost always useless, and even when they aren't they are +// usually a mistake. +package assign diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go index 9261db7e4..5978b9b1f 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package atomic defines an Analyzer that checks for common mistakes -// using the sync/atomic package. package atomic import ( + _ "embed" "go/ast" "go/token" "go/types" @@ -17,17 +16,13 @@ import ( "golang.org/x/tools/go/ast/inspector" ) -const Doc = `check for common mistakes using the sync/atomic package - -The atomic checker looks for assignment statements of the form: - - x = atomic.AddUint64(&x, 1) - -which are not atomic.` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "atomic", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "atomic"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic", Requires: []*analysis.Analyzer{inspect.Analyzer}, RunDespiteErrors: true, Run: run, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomic/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/atomic/doc.go new file mode 100644 index 000000000..5aafe25d3 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomic/doc.go @@ -0,0 +1,17 @@ +// Copyright 2023 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 atomic defines an Analyzer that checks for common mistakes +// using the sync/atomic package. +// +// # Analyzer atomic +// +// atomic: check for common mistakes using the sync/atomic package +// +// The atomic checker looks for assignment statements of the form: +// +// x = atomic.AddUint64(&x, 1) +// +// which are not atomic. +package atomic diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go index e2e1a4f67..fc2ce3052 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go @@ -25,6 +25,7 @@ const Doc = "check for non-64-bits-aligned arguments to sync/atomic functions" var Analyzer = &analysis.Analyzer{ Name: "atomicalign", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomicalign", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go index 0d8b0bf4f..4219f087b 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go @@ -22,6 +22,7 @@ const Doc = "check for common mistakes involving boolean operators" var Analyzer = &analysis.Analyzer{ Name: "bools", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/bools", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go index 02b7b18b3..ad42f39a8 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go @@ -22,6 +22,7 @@ import ( var Analyzer = &analysis.Analyzer{ Name: "buildssa", Doc: "build SSA-form IR for later passes", + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildssa", Run: run, ResultType: reflect.TypeOf(new(SSA)), } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go b/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go index 775e507a3..a2a4a89b3 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go @@ -25,6 +25,7 @@ const Doc = "check //go:build and // +build directives" var Analyzer = &analysis.Analyzer{ Name: "buildtag", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildtag", Run: runBuildTag, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index b61ee5c3d..afff0d82d 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -35,6 +35,7 @@ or slice to C, either directly, or via a pointer, array, or struct.` var Analyzer = &analysis.Analyzer{ Name: "cgocall", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/cgocall", RunDespiteErrors: true, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go b/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go index 64e184d34..20fb70806 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go @@ -37,6 +37,7 @@ should be replaced by: var Analyzer = &analysis.Analyzer{ Name: "composites", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/composites", Requires: []*analysis.Analyzer{inspect.Analyzer}, RunDespiteErrors: true, Run: run, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go index 8cc93e94d..b3ca8ada4 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go @@ -29,6 +29,7 @@ values should be referred to through a pointer.` var Analyzer = &analysis.Analyzer{ Name: "copylocks", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/copylocks", Requires: []*analysis.Analyzer{inspect.Analyzer}, RunDespiteErrors: true, Run: run, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go b/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go index 73746d6f0..d21adeee9 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/ctrlflow/ctrlflow.go @@ -24,6 +24,7 @@ import ( var Analyzer = &analysis.Analyzer{ Name: "ctrlflow", Doc: "build a control-flow graph", + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ctrlflow", Run: run, ResultType: reflect.TypeOf(new(CFGs)), FactTypes: []analysis.Fact{new(noReturn)}, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go index 9ea137386..afc4fdc85 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go @@ -28,6 +28,7 @@ errors is discouraged.` var Analyzer = &analysis.Analyzer{ Name: "deepequalerrors", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/deepequalerrors", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go index 96adad3ee..867fc26fa 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -25,6 +25,7 @@ of the second argument is not a pointer to a type implementing error.` var Analyzer = &analysis.Analyzer{ Name: "errorsas", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/errorsas", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/fieldalignment/fieldalignment.go b/vendor/golang.org/x/tools/go/analysis/passes/fieldalignment/fieldalignment.go index aff663046..012e2ecd0 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/fieldalignment/fieldalignment.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/fieldalignment/fieldalignment.go @@ -51,6 +51,7 @@ known as "false sharing" that slows down both goroutines. var Analyzer = &analysis.Analyzer{ Name: "fieldalignment", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/findcall/findcall.go b/vendor/golang.org/x/tools/go/analysis/passes/findcall/findcall.go index 27b1b8400..2671573d1 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/findcall/findcall.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/findcall/findcall.go @@ -26,6 +26,7 @@ of a particular name.` var Analyzer = &analysis.Analyzer{ Name: "findcall", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/findcall", Run: run, RunDespiteErrors: true, FactTypes: []analysis.Fact{new(foundFact)}, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go b/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go index 741492e47..0b3ded47e 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go @@ -20,6 +20,7 @@ const Doc = "report assembly that clobbers the frame pointer before saving it" var Analyzer = &analysis.Analyzer{ Name: "framepointer", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/framepointer", Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go index 3b9168c6c..61c3b764f 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go @@ -35,6 +35,7 @@ diagnostic for such mistakes.` var Analyzer = &analysis.Analyzer{ Name: "httpresponse", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/httpresponse", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/doc.go new file mode 100644 index 000000000..3d2b1a3dc --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/doc.go @@ -0,0 +1,24 @@ +// Copyright 2023 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 ifaceassert defines an Analyzer that flags +// impossible interface-interface type assertions. +// +// # Analyzer ifaceassert +// +// ifaceassert: detect impossible interface-to-interface type assertions +// +// This checker flags type assertions v.(T) and corresponding type-switch cases +// in which the static type V of v is an interface that cannot possibly implement +// the target interface T. This occurs when V and T contain methods with the same +// name but different signatures. Example: +// +// var v interface { +// Read() +// } +// _ = v.(io.Reader) +// +// The Read method in v has a different signature than the Read method in +// io.Reader, so this assertion cannot succeed. +package ifaceassert diff --git a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go index 30130f63e..cd4a47762 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/ifaceassert.go @@ -2,38 +2,26 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package ifaceassert defines an Analyzer that flags -// impossible interface-interface type assertions. package ifaceassert import ( + _ "embed" "go/ast" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" ) -const Doc = `detect impossible interface-to-interface type assertions - -This checker flags type assertions v.(T) and corresponding type-switch cases -in which the static type V of v is an interface that cannot possibly implement -the target interface T. This occurs when V and T contain methods with the same -name but different signatures. Example: - - var v interface { - Read() - } - _ = v.(io.Reader) - -The Read method in v has a different signature than the Read method in -io.Reader, so this assertion cannot succeed. -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "ifaceassert", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "ifaceassert"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go b/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go index 165c70cbd..3b121cb0c 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go @@ -38,6 +38,7 @@ import ( var Analyzer = &analysis.Analyzer{ Name: "inspect", Doc: "optimize AST traversal for later passes", + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/inspect", Run: run, RunDespiteErrors: true, ResultType: reflect.TypeOf(new(inspector.Inspector)), diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go new file mode 100644 index 000000000..0e175ca06 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go @@ -0,0 +1,113 @@ +// Copyright 2023 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 analysisutil + +import ( + "fmt" + "go/parser" + "go/token" + "strings" +) + +// MustExtractDoc is like [ExtractDoc] but it panics on error. +// +// To use, define a doc.go file such as: +// +// // Package halting defines an analyzer of program termination. +// // +// // # Analyzer halting +// // +// // halting: reports whether execution will halt. +// // +// // The halting analyzer reports a diagnostic for functions +// // that run forever. To suppress the diagnostics, try inserting +// // a 'break' statement into each loop. +// package halting +// +// import _ "embed" +// +// //go:embed doc.go +// var doc string +// +// And declare your analyzer as: +// +// var Analyzer = &analysis.Analyzer{ +// Name: "halting", +// Doc: analysisutil.MustExtractDoc(doc, "halting"), +// ... +// } +func MustExtractDoc(content, name string) string { + doc, err := ExtractDoc(content, name) + if err != nil { + panic(err) + } + return doc +} + +// ExtractDoc extracts a section of a package doc comment from the +// provided contents of an analyzer package's doc.go file. +// +// A section is a portion of the comment between one heading and +// the next, using this form: +// +// # Analyzer NAME +// +// NAME: SUMMARY +// +// Full description... +// +// where NAME matches the name argument, and SUMMARY is a brief +// verb-phrase that describes the analyzer. The following lines, up +// until the next heading or the end of the comment, contain the full +// description. ExtractDoc returns the portion following the colon, +// which is the form expected by Analyzer.Doc. +// +// Example: +// +// # Analyzer printf +// +// printf: checks consistency of calls to printf +// +// The printf analyzer checks consistency of calls to printf. +// Here is the complete description... +// +// This notation allows a single doc comment to provide documentation +// for multiple analyzers, each in its own section. +// The HTML anchors generated for each heading are predictable. +// +// It returns an error if the content was not a valid Go source file +// containing a package doc comment with a heading of the required +// form. +// +// This machinery enables the package documentation (typically +// accessible via the web at https://pkg.go.dev/) and the command +// documentation (typically printed to a terminal) to be derived from +// the same source and formatted appropriately. +func ExtractDoc(content, name string) (string, error) { + if content == "" { + return "", fmt.Errorf("empty Go source file") + } + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "", content, parser.ParseComments|parser.PackageClauseOnly) + if err != nil { + return "", fmt.Errorf("not a Go source file") + } + if f.Doc == nil { + return "", fmt.Errorf("Go source file has no package doc comment") + } + for _, section := range strings.Split(f.Doc.Text(), "\n# ") { + if body := strings.TrimPrefix(section, "Analyzer "+name); body != section && + body != "" && + body[0] == '\r' || body[0] == '\n' { + body = strings.TrimSpace(body) + rest := strings.TrimPrefix(body, name+":") + if rest == body { + return "", fmt.Errorf("'Analyzer %s' heading not followed by '%s: summary...' line", name, name) + } + return strings.TrimSpace(rest), nil + } + } + return "", fmt.Errorf("package doc comment contains no 'Analyzer %s' heading", name) +} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go new file mode 100644 index 000000000..dc544df1b --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go @@ -0,0 +1,68 @@ +// Copyright 2023 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 loopclosure defines an Analyzer that checks for references to +// enclosing loop variables from within nested functions. +// +// # Analyzer loopclosure +// +// loopclosure: check references to loop variables from within nested functions +// +// This analyzer reports places where a function literal references the +// iteration variable of an enclosing loop, and the loop calls the function +// in such a way (e.g. with go or defer) that it may outlive the loop +// iteration and possibly observe the wrong value of the variable. +// +// In this example, all the deferred functions run after the loop has +// completed, so all observe the final value of v. +// +// for _, v := range list { +// defer func() { +// use(v) // incorrect +// }() +// } +// +// One fix is to create a new variable for each iteration of the loop: +// +// for _, v := range list { +// v := v // new var per iteration +// defer func() { +// use(v) // ok +// }() +// } +// +// The next example uses a go statement and has a similar problem. +// In addition, it has a data race because the loop updates v +// concurrent with the goroutines accessing it. +// +// for _, v := range elem { +// go func() { +// use(v) // incorrect, and a data race +// }() +// } +// +// A fix is the same as before. The checker also reports problems +// in goroutines started by golang.org/x/sync/errgroup.Group. +// A hard-to-spot variant of this form is common in parallel tests: +// +// func Test(t *testing.T) { +// for _, test := range tests { +// t.Run(test.name, func(t *testing.T) { +// t.Parallel() +// use(test) // incorrect, and a data race +// }) +// } +// } +// +// The t.Parallel() call causes the rest of the function to execute +// concurrent with the loop. +// +// The analyzer reports references only in the last statement, +// as it is not deep enough to understand the effects of subsequent +// statements that might render the reference benign. +// ("Last statement" is defined recursively in compound +// statements such as if, switch, and select.) +// +// See: https://golang.org/doc/go_faq.html#closures_and_goroutines +package loopclosure diff --git a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go index ae5b4151d..5620c35fa 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go @@ -2,82 +2,27 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package loopclosure defines an Analyzer that checks for references to -// enclosing loop variables from within nested functions. package loopclosure import ( + _ "embed" "go/ast" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" ) -const Doc = `check references to loop variables from within nested functions - -This analyzer reports places where a function literal references the -iteration variable of an enclosing loop, and the loop calls the function -in such a way (e.g. with go or defer) that it may outlive the loop -iteration and possibly observe the wrong value of the variable. - -In this example, all the deferred functions run after the loop has -completed, so all observe the final value of v. - - for _, v := range list { - defer func() { - use(v) // incorrect - }() - } - -One fix is to create a new variable for each iteration of the loop: - - for _, v := range list { - v := v // new var per iteration - defer func() { - use(v) // ok - }() - } - -The next example uses a go statement and has a similar problem. -In addition, it has a data race because the loop updates v -concurrent with the goroutines accessing it. - - for _, v := range elem { - go func() { - use(v) // incorrect, and a data race - }() - } - -A fix is the same as before. The checker also reports problems -in goroutines started by golang.org/x/sync/errgroup.Group. -A hard-to-spot variant of this form is common in parallel tests: - - func Test(t *testing.T) { - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - use(test) // incorrect, and a data race - }) - } - } - -The t.Parallel() call causes the rest of the function to execute -concurrent with the loop. - -The analyzer reports references only in the last statement, -as it is not deep enough to understand the effects of subsequent -statements that might render the reference benign. -("Last statement" is defined recursively in compound -statements such as if, switch, and select.) - -See: https://golang.org/doc/go_faq.html#closures_and_goroutines` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "loopclosure", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "loopclosure"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/doc.go new file mode 100644 index 000000000..28bf6c7e2 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/doc.go @@ -0,0 +1,16 @@ +// Copyright 2023 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 lostcancel defines an Analyzer that checks for failure to +// call a context cancellation function. +// +// # Analyzer lostcancel +// +// lostcancel: check cancel func returned by context.WithCancel is called +// +// The cancellation function returned by context.WithCancel, WithTimeout, +// and WithDeadline must be called or the new context will remain live +// until its parent context is cancelled. +// (The background context is never cancelled.) +package lostcancel diff --git a/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go b/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go index de6f840f6..b59f80ca5 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package lostcancel defines an Analyzer that checks for failure to -// call a context cancellation function. package lostcancel import ( + _ "embed" "fmt" "go/ast" "go/types" @@ -14,20 +13,18 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/ctrlflow" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/cfg" ) -const Doc = `check cancel func returned by context.WithCancel is called - -The cancellation function returned by context.WithCancel, WithTimeout, -and WithDeadline must be called or the new context will remain live -until its parent context is cancelled. -(The background context is never cancelled.)` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "lostcancel", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "lostcancel"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel", Run: run, Requires: []*analysis.Analyzer{ inspect.Analyzer, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/doc.go new file mode 100644 index 000000000..07f79332b --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/doc.go @@ -0,0 +1,13 @@ +// Copyright 2023 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 nilfunc defines an Analyzer that checks for useless +// comparisons against nil. +// +// # Analyzer nilfunc +// +// nilfunc: check for useless comparisons between functions and nil +// +// A useless comparison is one like f == nil as opposed to f() == nil. +package nilfunc diff --git a/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go b/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go index e4c66df6d..511885075 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go @@ -7,12 +7,14 @@ package nilfunc import ( + _ "embed" "go/ast" "go/token" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/internal/typeparams" ) @@ -21,9 +23,13 @@ const Doc = `check for useless comparisons between functions and nil A useless comparison is one like f == nil as opposed to f() == nil.` +//go:embed doc.go +var doc string + var Analyzer = &analysis.Analyzer{ Name: "nilfunc", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "nilfunc"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/nilness/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/nilness/doc.go new file mode 100644 index 000000000..212263741 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/nilness/doc.go @@ -0,0 +1,45 @@ +// Copyright 2023 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 nilness inspects the control-flow graph of an SSA function +// and reports errors such as nil pointer dereferences and degenerate +// nil pointer comparisons. +// +// # Analyzer nilness +// +// nilness: check for redundant or impossible nil comparisons +// +// The nilness checker inspects the control-flow graph of each function in +// a package and reports nil pointer dereferences, degenerate nil +// pointers, and panics with nil values. A degenerate comparison is of the form +// x==nil or x!=nil where x is statically known to be nil or non-nil. These are +// often a mistake, especially in control flow related to errors. Panics with nil +// values are checked because they are not detectable by +// +// if r := recover(); r != nil { +// +// This check reports conditions such as: +// +// if f == nil { // impossible condition (f is a function) +// } +// +// and: +// +// p := &v +// ... +// if p != nil { // tautological condition +// } +// +// and: +// +// if p == nil { +// print(*p) // nil dereference +// } +// +// and: +// +// if p == nil { +// panic(p) +// } +package nilness diff --git a/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go b/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go index 6849c33cc..d1ca0748e 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go @@ -2,61 +2,28 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package nilness inspects the control-flow graph of an SSA function -// and reports errors such as nil pointer dereferences and degenerate -// nil pointer comparisons. package nilness import ( + _ "embed" "fmt" "go/token" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/buildssa" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ssa" "golang.org/x/tools/internal/typeparams" ) -const Doc = `check for redundant or impossible nil comparisons - -The nilness checker inspects the control-flow graph of each function in -a package and reports nil pointer dereferences, degenerate nil -pointers, and panics with nil values. A degenerate comparison is of the form -x==nil or x!=nil where x is statically known to be nil or non-nil. These are -often a mistake, especially in control flow related to errors. Panics with nil -values are checked because they are not detectable by - - if r := recover(); r != nil { - -This check reports conditions such as: - - if f == nil { // impossible condition (f is a function) - } - -and: - - p := &v - ... - if p != nil { // tautological condition - } - -and: - - if p == nil { - print(*p) // nil dereference - } - -and: - - if p == nil { - panic(p) - } -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "nilness", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "nilness"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness", Run: run, Requires: []*analysis.Analyzer{buildssa.Analyzer}, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/pkgfact/pkgfact.go b/vendor/golang.org/x/tools/go/analysis/passes/pkgfact/pkgfact.go index f4f5616e5..4bf33d45f 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/pkgfact/pkgfact.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/pkgfact/pkgfact.go @@ -38,6 +38,7 @@ import ( var Analyzer = &analysis.Analyzer{ Name: "pkgfact", Doc: "gather name/value pairs from constant declarations", + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/pkgfact", Run: run, FactTypes: []analysis.Fact{new(pairsFact)}, ResultType: reflect.TypeOf(map[string]string{}), diff --git a/vendor/golang.org/x/tools/go/analysis/passes/printf/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/printf/doc.go new file mode 100644 index 000000000..1ee16126a --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/printf/doc.go @@ -0,0 +1,47 @@ +// Copyright 2023 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 printf defines an Analyzer that checks consistency +// of Printf format strings and arguments. +// +// # Analyzer printf +// +// printf: check consistency of Printf format strings and arguments +// +// The check applies to calls of the formatting functions such as +// [fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of +// those functions. +// +// In this example, the %d format operator requires an integer operand: +// +// fmt.Printf("%d", "hello") // fmt.Printf format %d has arg "hello" of wrong type string +// +// See the documentation of the fmt package for the complete set of +// format operators and their operand types. +// +// To enable printf checking on a function that is not found by this +// analyzer's heuristics (for example, because control is obscured by +// dynamic method calls), insert a bogus call: +// +// func MyPrintf(format string, args ...any) { +// if false { +// _ = fmt.Sprintf(format, args...) // enable printf checker +// } +// ... +// } +// +// The -funcs flag specifies a comma-separated list of names of additional +// known formatting functions or methods. If the name contains a period, +// it must denote a specific function using one of the following forms: +// +// dir/pkg.Function +// dir/pkg.Type.Method +// (*dir/pkg.Type).Method +// +// Otherwise the name is interpreted as a case-insensitive unqualified +// identifier such as "errorf". Either way, if a listed name ends in f, the +// function is assumed to be Printf-like, taking a format string before the +// argument list. Otherwise it is assumed to be Print-like, taking a list +// of arguments with no format string. +package printf diff --git a/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index daaf709a4..919edac46 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -2,12 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package printf defines an Analyzer that checks consistency -// of Printf format strings and arguments. package printf import ( "bytes" + _ "embed" "fmt" "go/ast" "go/constant" @@ -32,43 +31,19 @@ func init() { Analyzer.Flags.Var(isPrint, "funcs", "comma-separated list of print function names to check") } +//go:embed doc.go +var doc string + var Analyzer = &analysis.Analyzer{ Name: "printf", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "printf"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, ResultType: reflect.TypeOf((*Result)(nil)), FactTypes: []analysis.Fact{new(isWrapper)}, } -const Doc = `check consistency of Printf format strings and arguments - -The check applies to known functions (for example, those in package fmt) -as well as any detected wrappers of known functions. - -A function that wants to avail itself of printf checking but is not -found by this analyzer's heuristics (for example, due to use of -dynamic calls) can insert a bogus call: - - if false { - _ = fmt.Sprintf(format, args...) // enable printf checking - } - -The -funcs flag specifies a comma-separated list of names of additional -known formatting functions or methods. If the name contains a period, -it must denote a specific function using one of the following forms: - - dir/pkg.Function - dir/pkg.Type.Method - (*dir/pkg.Type).Method - -Otherwise the name is interpreted as a case-insensitive unqualified -identifier such as "errorf". Either way, if a listed name ends in f, the -function is assumed to be Printf-like, taking a format string before the -argument list. Otherwise it is assumed to be Print-like, taking a list -of arguments with no format string. -` - // Kind is a kind of fmt function behavior. type Kind int @@ -340,9 +315,10 @@ func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, k // example, fmt.Printf forwards to fmt.Fprintf. We avoid relying on the // driver applying analyzers to standard packages because "go vet" does // not do so with gccgo, and nor do some other build systems. -// TODO(adonovan): eliminate the redundant facts once this restriction -// is lifted. var isPrint = stringSet{ + "fmt.Appendf": true, + "fmt.Append": true, + "fmt.Appendln": true, "fmt.Errorf": true, "fmt.Fprint": true, "fmt.Fprintf": true, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/doc.go new file mode 100644 index 000000000..32f342b97 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/doc.go @@ -0,0 +1,27 @@ +// Copyright 2023 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 reflectvaluecompare defines an Analyzer that checks for accidentally +// using == or reflect.DeepEqual to compare reflect.Value values. +// See issues 43993 and 18871. +// +// # Analyzer reflectvaluecompare +// +// reflectvaluecompare: check for comparing reflect.Value values with == or reflect.DeepEqual +// +// The reflectvaluecompare checker looks for expressions of the form: +// +// v1 == v2 +// v1 != v2 +// reflect.DeepEqual(v1, v2) +// +// where v1 or v2 are reflect.Values. Comparing reflect.Values directly +// is almost certainly not correct, as it compares the reflect package's +// internal representation, not the underlying value. +// Likely what is intended is: +// +// v1.Interface() == v2.Interface() +// v1.Interface() != v2.Interface() +// reflect.DeepEqual(v1.Interface(), v2.Interface()) +package reflectvaluecompare diff --git a/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go b/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go index ef21f0e7d..27677139e 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go @@ -2,43 +2,28 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package reflectvaluecompare defines an Analyzer that checks for accidentally -// using == or reflect.DeepEqual to compare reflect.Value values. -// See issues 43993 and 18871. package reflectvaluecompare import ( + _ "embed" "go/ast" "go/token" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" ) -const Doc = `check for comparing reflect.Value values with == or reflect.DeepEqual - -The reflectvaluecompare checker looks for expressions of the form: - - v1 == v2 - v1 != v2 - reflect.DeepEqual(v1, v2) - -where v1 or v2 are reflect.Values. Comparing reflect.Values directly -is almost certainly not correct, as it compares the reflect package's -internal representation, not the underlying value. -Likely what is intended is: - - v1.Interface() == v2.Interface() - v1.Interface() != v2.Interface() - reflect.DeepEqual(v1.Interface(), v2.Interface()) -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "reflectvaluecompare", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "reflectvaluecompare"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/reflectvaluecompare", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/shadow/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/shadow/doc.go new file mode 100644 index 000000000..781fd2eb8 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/shadow/doc.go @@ -0,0 +1,33 @@ +// Copyright 2023 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 shadow defines an Analyzer that checks for shadowed variables. +// +// # Analyzer shadow +// +// shadow: check for possible unintended shadowing of variables +// +// This analyzer check for shadowed variables. +// A shadowed variable is a variable declared in an inner scope +// with the same name and type as a variable in an outer scope, +// and where the outer variable is mentioned after the inner one +// is declared. +// +// (This definition can be refined; the module generates too many +// false positives and is not yet enabled by default.) +// +// For example: +// +// func BadRead(f *os.File, buf []byte) error { +// var err error +// for { +// n, err := f.Read(buf) // shadows the function variable 'err' +// if err != nil { +// break // causes return of wrong value +// } +// foo(buf) +// } +// return err +// } +package shadow diff --git a/vendor/golang.org/x/tools/go/analysis/passes/shadow/shadow.go b/vendor/golang.org/x/tools/go/analysis/passes/shadow/shadow.go index a19cecd14..30258c991 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/shadow/shadow.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/shadow/shadow.go @@ -2,50 +2,29 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package shadow defines an Analyzer that checks for shadowed variables. package shadow import ( + _ "embed" "go/ast" "go/token" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" ) // NOTE: Experimental. Not part of the vet suite. -const Doc = `check for possible unintended shadowing of variables - -This analyzer check for shadowed variables. -A shadowed variable is a variable declared in an inner scope -with the same name and type as a variable in an outer scope, -and where the outer variable is mentioned after the inner one -is declared. - -(This definition can be refined; the module generates too many -false positives and is not yet enabled by default.) - -For example: - - func BadRead(f *os.File, buf []byte) error { - var err error - for { - n, err := f.Read(buf) // shadows the function variable 'err' - if err != nil { - break // causes return of wrong value - } - foo(buf) - } - return err - } -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "shadow", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "shadow"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shadow", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go b/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go index e968f27b4..bafb9112e 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go @@ -29,6 +29,7 @@ const Doc = "check for shifts that equal or exceed the width of the integer" var Analyzer = &analysis.Analyzer{ Name: "shift", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shift", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/doc.go new file mode 100644 index 000000000..583fed014 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/doc.go @@ -0,0 +1,17 @@ +// Copyright 2023 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 sigchanyzer defines an Analyzer that detects +// misuse of unbuffered signal as argument to signal.Notify. +// +// # Analyzer sigchanyzer +// +// sigchanyzer: check for unbuffered channel of os.Signal +// +// This checker reports call expression of the form +// +// signal.Notify(c <-chan os.Signal, sig ...os.Signal), +// +// where c is an unbuffered channel, which can be at risk of missing the signal. +package sigchanyzer diff --git a/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go b/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go index c490a84ea..d0f16d380 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go @@ -8,6 +8,7 @@ package sigchanyzer import ( "bytes" + _ "embed" "go/ast" "go/format" "go/token" @@ -15,18 +16,18 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" ) -const Doc = `check for unbuffered channel of os.Signal - -This checker reports call expression of the form signal.Notify(c <-chan os.Signal, sig ...os.Signal), -where c is an unbuffered channel, which can be at risk of missing the signal.` +//go:embed doc.go +var doc string // Analyzer describes sigchanyzer analysis function detector. var Analyzer = &analysis.Analyzer{ Name: "sigchanyzer", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "sigchanyzer"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sigchanyzer", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go b/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go index f85837d66..eecb3b8bd 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go @@ -27,11 +27,13 @@ the interface{} value passed to sort.Slice is actually a slice.` var Analyzer = &analysis.Analyzer{ Name: "sortslice", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sortslice", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } func run(pass *analysis.Pass) (interface{}, error) { + // TODO(adonovan): opt: first check for import "sort". inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ diff --git a/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/doc.go new file mode 100644 index 000000000..9ed88698d --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/doc.go @@ -0,0 +1,30 @@ +// Copyright 2023 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 stdmethods defines an Analyzer that checks for misspellings +// in the signatures of methods similar to well-known interfaces. +// +// # Analyzer stdmethods +// +// stdmethods: check signature of methods of well-known interfaces +// +// Sometimes a type may be intended to satisfy an interface but may fail to +// do so because of a mistake in its method signature. +// For example, the result of this WriteTo method should be (int64, error), +// not error, to satisfy io.WriterTo: +// +// type myWriterTo struct{...} +// func (myWriterTo) WriteTo(w io.Writer) error { ... } +// +// This check ensures that each method whose name matches one of several +// well-known interface methods from the standard library has the correct +// signature for that interface. +// +// Checked method names include: +// +// Format GobEncode GobDecode MarshalJSON MarshalXML +// Peek ReadByte ReadFrom ReadRune Scan Seek +// UnmarshalJSON UnreadByte UnreadRune WriteByte +// WriteTo +package stdmethods diff --git a/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go b/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go index 41f455d10..28f51b1ec 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go @@ -2,44 +2,27 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package stdmethods defines an Analyzer that checks for misspellings -// in the signatures of methods similar to well-known interfaces. package stdmethods import ( + _ "embed" "go/ast" "go/types" "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" ) -const Doc = `check signature of methods of well-known interfaces - -Sometimes a type may be intended to satisfy an interface but may fail to -do so because of a mistake in its method signature. -For example, the result of this WriteTo method should be (int64, error), -not error, to satisfy io.WriterTo: - - type myWriterTo struct{...} - func (myWriterTo) WriteTo(w io.Writer) error { ... } - -This check ensures that each method whose name matches one of several -well-known interface methods from the standard library has the correct -signature for that interface. - -Checked method names include: - Format GobEncode GobDecode MarshalJSON MarshalXML - Peek ReadByte ReadFrom ReadRune Scan Seek - UnmarshalJSON UnreadByte UnreadRune WriteByte - WriteTo -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "stdmethods", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "stdmethods"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/doc.go new file mode 100644 index 000000000..205cd6401 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/doc.go @@ -0,0 +1,21 @@ +// Copyright 2023 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 stringintconv defines an Analyzer that flags type conversions +// from integers to strings. +// +// # Analyzer stringintconv +// +// stringintconv: check for string(int) conversions +// +// This checker flags conversions of the form string(x) where x is an integer +// (but not byte or rune) type. Such conversions are discouraged because they +// return the UTF-8 representation of the Unicode code point x, and not a decimal +// string representation of x as one might expect. Furthermore, if x denotes an +// invalid code point, the conversion cannot be statically rejected. +// +// For conversions that intend on using the code point, consider replacing them +// with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the +// string representation of the value in the desired base. +package stringintconv diff --git a/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go b/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go index e41de809d..bb04dae62 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package stringintconv defines an Analyzer that flags type conversions -// from integers to strings. package stringintconv import ( + _ "embed" "fmt" "go/ast" "go/types" @@ -14,26 +13,18 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/internal/typeparams" ) -const Doc = `check for string(int) conversions - -This checker flags conversions of the form string(x) where x is an integer -(but not byte or rune) type. Such conversions are discouraged because they -return the UTF-8 representation of the Unicode code point x, and not a decimal -string representation of x as one might expect. Furthermore, if x denotes an -invalid code point, the conversion cannot be statically rejected. - -For conversions that intend on using the code point, consider replacing them -with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the -string representation of the value in the desired base. -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "stringintconv", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "stringintconv"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go b/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go index f0b15051c..a0beb46bd 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go @@ -28,6 +28,7 @@ Also report certain struct tags (json, xml) used with unexported fields.` var Analyzer = &analysis.Analyzer{ Name: "structtag", Doc: Doc, + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/structtag", Requires: []*analysis.Analyzer{inspect.Analyzer}, RunDespiteErrors: true, Run: run, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go new file mode 100644 index 000000000..a68adb12b --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go @@ -0,0 +1,22 @@ +// Copyright 2023 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 testinggoroutine defines an Analyzerfor detecting calls to +// Fatal from a test goroutine. +// +// # Analyzer testinggoroutine +// +// testinggoroutine: report calls to (*testing.T).Fatal from goroutines started by a test. +// +// Functions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and +// Skip{,f,Now} methods of *testing.T, must be called from the test goroutine itself. +// This checker detects calls to these functions that occur within a goroutine +// started by the test. For example: +// +// func TestFoo(t *testing.T) { +// go func() { +// t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine +// }() +// } +package testinggoroutine diff --git a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go index 7ea8f77e3..907b71503 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go @@ -5,6 +5,7 @@ package testinggoroutine import ( + _ "embed" "go/ast" "golang.org/x/tools/go/analysis" @@ -14,23 +15,13 @@ import ( "golang.org/x/tools/internal/typeparams" ) -const Doc = `report calls to (*testing.T).Fatal from goroutines started by a test. - -Functions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and -Skip{,f,Now} methods of *testing.T, must be called from the test goroutine itself. -This checker detects calls to these functions that occur within a goroutine -started by the test. For example: - -func TestFoo(t *testing.T) { - go func() { - t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine - }() -} -` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "testinggoroutine", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "testinggoroutine"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/tests/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/tests/doc.go new file mode 100644 index 000000000..3ae27db9c --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/tests/doc.go @@ -0,0 +1,18 @@ +// Copyright 2023 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 tests defines an Analyzer that checks for common mistaken +// usages of tests and examples. +// +// # Analyzer tests +// +// tests: check for common mistaken usages of tests and examples +// +// The tests checker walks Test, Benchmark, Fuzzing and Example functions checking +// malformed names, wrong signatures and examples documenting non-existent +// identifiers. +// +// Please see the documentation for package testing in golang.org/pkg/testing +// for the conventions that are enforced for Tests, Benchmarks, and Examples. +package tests diff --git a/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go b/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go index 935aad00c..9589a46a5 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package tests defines an Analyzer that checks for common mistaken -// usages of tests and examples. package tests import ( + _ "embed" "fmt" "go/ast" "go/token" @@ -17,22 +16,17 @@ import ( "unicode/utf8" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/internal/analysisinternal" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/internal/typeparams" ) -const Doc = `check for common mistaken usages of tests and examples - -The tests checker walks Test, Benchmark and Example functions checking -malformed names, wrong signatures and examples documenting non-existent -identifiers. - -Please see the documentation for package testing in golang.org/pkg/testing -for the conventions that are enforced for Tests, Benchmarks, and Examples.` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "tests", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "tests"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests", Run: run, } @@ -73,9 +67,7 @@ func run(pass *analysis.Pass) (interface{}, error) { checkTest(pass, fn, "Test") case strings.HasPrefix(fn.Name.Name, "Benchmark"): checkTest(pass, fn, "Benchmark") - } - // run fuzz tests diagnostics only for 1.18 i.e. when analysisinternal.DiagnoseFuzzTests is turned on. - if strings.HasPrefix(fn.Name.Name, "Fuzz") && analysisinternal.DiagnoseFuzzTests { + case strings.HasPrefix(fn.Name.Name, "Fuzz"): checkTest(pass, fn, "Fuzz") checkFuzz(pass, fn) } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/doc.go new file mode 100644 index 000000000..5c665b298 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/doc.go @@ -0,0 +1,15 @@ +// Copyright 2023 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 timeformat defines an Analyzer that checks for the use +// of time.Format or time.Parse calls with a bad format. +// +// # Analyzer timeformat +// +// timeformat: check for calls of (time.Time).Format or time.Parse with 2006-02-01 +// +// The timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm) +// format. Internationally, "yyyy-dd-mm" does not occur in common calendar date +// standards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended. +package timeformat diff --git a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go index acb198f95..f9b79078c 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go @@ -7,6 +7,7 @@ package timeformat import ( + _ "embed" "go/ast" "go/constant" "go/token" @@ -15,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" ) @@ -29,9 +31,13 @@ format. Internationally, "yyyy-dd-mm" does not occur in common calendar date standards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended. ` +//go:embed doc.go +var doc string + var Analyzer = &analysis.Analyzer{ Name: "timeformat", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "timeformat"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/timeformat", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/doc.go new file mode 100644 index 000000000..5781bbd32 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/doc.go @@ -0,0 +1,14 @@ +// Copyright 2023 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. + +// The unmarshal package defines an Analyzer that checks for passing +// non-pointer or non-interface types to unmarshal and decode functions. +// +// # Analyzer unmarshal +// +// unmarshal: report passing non-pointer or non-interface values to unmarshal +// +// The unmarshal analysis reports calls to functions such as json.Unmarshal +// in which the argument type is not a pointer or an interface. +package unmarshal diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go index 5129048a0..28f552df8 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go @@ -2,29 +2,28 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The unmarshal package defines an Analyzer that checks for passing -// non-pointer or non-interface types to unmarshal and decode functions. package unmarshal import ( + _ "embed" "go/ast" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/typeparams" ) -const Doc = `report passing non-pointer or non-interface values to unmarshal - -The unmarshal analysis reports calls to functions such as json.Unmarshal -in which the argument type is not a pointer or an interface.` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "unmarshal", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "unmarshal"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go new file mode 100644 index 000000000..d17d0d944 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go @@ -0,0 +1,14 @@ +// Copyright 2023 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 unreachable defines an Analyzer that checks for unreachable code. +// +// # Analyzer unreachable +// +// unreachable: check for unreachable code +// +// The unreachable analyzer finds statements that execution can never reach +// because they are preceded by an return statement, a call to panic, an +// infinite loop, or similar constructs. +package unreachable diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go b/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go index 90896dd1b..b810db7ee 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go @@ -2,30 +2,29 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package unreachable defines an Analyzer that checks for unreachable code. package unreachable // TODO(adonovan): use the new cfg package, which is more precise. import ( + _ "embed" "go/ast" "go/token" "log" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" ) -const Doc = `check for unreachable code - -The unreachable analyzer finds statements that execution can never reach -because they are preceded by an return statement, a call to panic, an -infinite loop, or similar constructs.` +//go:embed doc.go +var doc string var Analyzer = &analysis.Analyzer{ Name: "unreachable", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "unreachable"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable", Requires: []*analysis.Analyzer{inspect.Analyzer}, RunDespiteErrors: true, Run: run, diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go new file mode 100644 index 000000000..524fd0463 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go @@ -0,0 +1,17 @@ +// Copyright 2023 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 unsafeptr defines an Analyzer that checks for invalid +// conversions of uintptr to unsafe.Pointer. +// +// # Analyzer unsafeptr +// +// unsafeptr: check for invalid conversions of uintptr to unsafe.Pointer +// +// The unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer +// to convert integers to pointers. A conversion from uintptr to +// unsafe.Pointer is invalid if it implies that there is a uintptr-typed +// word in memory that holds a pointer value, because that word will be +// invisible to stack copying and to the garbage collector.` +package unsafeptr diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go index ed86e5ebf..b1a32f249 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go @@ -7,6 +7,7 @@ package unsafeptr import ( + _ "embed" "go/ast" "go/token" "go/types" @@ -25,9 +26,13 @@ unsafe.Pointer is invalid if it implies that there is a uintptr-typed word in memory that holds a pointer value, because that word will be invisible to stack copying and to the garbage collector.` +//go:embed doc.go +var doc string + var Analyzer = &analysis.Analyzer{ Name: "unsafeptr", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "unsafeptr"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go new file mode 100644 index 000000000..0a713ca0d --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go @@ -0,0 +1,17 @@ +// Copyright 2023 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 unusedresult defines an analyzer that checks for unused +// results of calls to certain pure functions. +// +// # Analyzer unusedresult +// +// unusedresult: check for unused results of calls to some functions +// +// Some functions like fmt.Errorf return a result and have no side effects, +// so it is always a mistake to discard the result. This analyzer reports +// calls to certain functions in which the result of the call is ignored. +// +// The set of functions may be controlled using flags. +package unusedresult diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go index 06747ba72..051bc7c81 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go @@ -7,6 +7,7 @@ package unusedresult import ( + _ "embed" "go/ast" "go/token" "go/types" @@ -20,10 +21,6 @@ import ( "golang.org/x/tools/internal/typeparams" ) -// TODO(adonovan): make this analysis modular: export a mustUseResult -// fact for each function that tail-calls one of the functions that we -// check, and check those functions too. - const Doc = `check for unused results of calls to some functions Some functions like fmt.Errorf return a result and have no side effects, @@ -32,9 +29,13 @@ calls to certain functions in which the result of the call is ignored. The set of functions may be controlled using flags.` +//go:embed doc.go +var doc string + var Analyzer = &analysis.Analyzer{ Name: "unusedresult", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "unusedresult"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } @@ -43,8 +44,27 @@ var Analyzer = &analysis.Analyzer{ var funcs, stringMethods stringSetFlag func init() { - // TODO(adonovan): provide a comment syntax to allow users to - // add their functions to this set using facts. + // TODO(adonovan): provide a comment or declaration syntax to + // allow users to add their functions to this set using facts. + // For example: + // + // func ignoringTheErrorWouldBeVeryBad() error { + // type mustUseResult struct{} // enables vet unusedresult check + // ... + // } + // + // ignoringTheErrorWouldBeVeryBad() // oops + // + + // Also, it is tempting to make this analysis modular: one + // could export a "mustUseResult" fact for each function that + // tail-calls one of the functions that we check, and check + // those functions too. + // + // However, just because you must use the result of + // fmt.Sprintf doesn't mean you need to use the result of + // every function that returns a formatted string: + // it may have other results and effects. funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse,context.WithValue,context.WithCancel,context.WithDeadline,context.WithTimeout") Analyzer.Flags.Var(&funcs, "funcs", "comma-separated list of functions whose results must be used") diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/doc.go new file mode 100644 index 000000000..de10dc8c8 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/doc.go @@ -0,0 +1,34 @@ +// Copyright 2023 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 unusedwrite checks for unused writes to the elements of a struct or array object. +// +// # Analyzer unusedwrite +// +// unusedwrite: checks for unused writes +// +// The analyzer reports instances of writes to struct fields and +// arrays that are never read. Specifically, when a struct object +// or an array is copied, its elements are copied implicitly by +// the compiler, and any element write to this copy does nothing +// with the original object. +// +// For example: +// +// type T struct { x int } +// +// func f(input []T) { +// for i, v := range input { // v is a copy +// v.x = i // unused write to field x +// } +// } +// +// Another example is about non-pointer receiver: +// +// type T struct { x int } +// +// func (t T) f() { // t is a copy +// t.x = i // unused write to field x +// } +package unusedwrite diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/unusedwrite.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/unusedwrite.go index 9cc45e0a3..f5d0f116c 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/unusedwrite.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedwrite/unusedwrite.go @@ -2,49 +2,28 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package unusedwrite checks for unused writes to the elements of a struct or array object. package unusedwrite import ( + _ "embed" "fmt" "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/buildssa" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ssa" ) -// Doc is a documentation string. -const Doc = `checks for unused writes - -The analyzer reports instances of writes to struct fields and -arrays that are never read. Specifically, when a struct object -or an array is copied, its elements are copied implicitly by -the compiler, and any element write to this copy does nothing -with the original object. - -For example: - - type T struct { x int } - func f(input []T) { - for i, v := range input { // v is a copy - v.x = i // unused write to field x - } - } - -Another example is about non-pointer receiver: - - type T struct { x int } - func (t T) f() { // t is a copy - t.x = i // unused write to field x - } -` +//go:embed doc.go +var doc string // Analyzer reports instances of writes to struct fields and arrays // that are never read. var Analyzer = &analysis.Analyzer{ Name: "unusedwrite", - Doc: Doc, + Doc: analysisutil.MustExtractDoc(doc, "unusedwrite"), + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedwrite", Requires: []*analysis.Analyzer{buildssa.Analyzer}, Run: run, } diff --git a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go deleted file mode 100644 index d15f0eb7a..000000000 --- a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2020 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 analysisinternal provides gopls' internal analyses with a -// number of helper functions that operate on typed syntax trees. -package analysisinternal - -import ( - "bytes" - "fmt" - "go/ast" - "go/token" - "go/types" - "strconv" -) - -// DiagnoseFuzzTests controls whether the 'tests' analyzer diagnoses fuzz tests -// in Go 1.18+. -var DiagnoseFuzzTests bool = false - -func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos { - // Get the end position for the type error. - offset, end := fset.PositionFor(start, false).Offset, start - if offset >= len(src) { - return end - } - if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 { - end = start + token.Pos(width) - } - return end -} - -func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { - under := typ - if n, ok := typ.(*types.Named); ok { - under = n.Underlying() - } - switch u := under.(type) { - case *types.Basic: - switch { - case u.Info()&types.IsNumeric != 0: - return &ast.BasicLit{Kind: token.INT, Value: "0"} - case u.Info()&types.IsBoolean != 0: - return &ast.Ident{Name: "false"} - case u.Info()&types.IsString != 0: - return &ast.BasicLit{Kind: token.STRING, Value: `""`} - default: - panic("unknown basic type") - } - case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array: - return ast.NewIdent("nil") - case *types.Struct: - texpr := TypeExpr(f, pkg, typ) // typ because we want the name here. - if texpr == nil { - return nil - } - return &ast.CompositeLit{ - Type: texpr, - } - } - return nil -} - -// IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of -// analysisinternal.ZeroValue) -func IsZeroValue(expr ast.Expr) bool { - switch e := expr.(type) { - case *ast.BasicLit: - return e.Value == "0" || e.Value == `""` - case *ast.Ident: - return e.Name == "nil" || e.Name == "false" - default: - return false - } -} - -// TypeExpr returns syntax for the specified type. References to -// named types from packages other than pkg are qualified by an appropriate -// package name, as defined by the import environment of file. -func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { - switch t := typ.(type) { - case *types.Basic: - switch t.Kind() { - case types.UnsafePointer: - return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")} - default: - return ast.NewIdent(t.Name()) - } - case *types.Pointer: - x := TypeExpr(f, pkg, t.Elem()) - if x == nil { - return nil - } - return &ast.UnaryExpr{ - Op: token.MUL, - X: x, - } - case *types.Array: - elt := TypeExpr(f, pkg, t.Elem()) - if elt == nil { - return nil - } - return &ast.ArrayType{ - Len: &ast.BasicLit{ - Kind: token.INT, - Value: fmt.Sprintf("%d", t.Len()), - }, - Elt: elt, - } - case *types.Slice: - elt := TypeExpr(f, pkg, t.Elem()) - if elt == nil { - return nil - } - return &ast.ArrayType{ - Elt: elt, - } - case *types.Map: - key := TypeExpr(f, pkg, t.Key()) - value := TypeExpr(f, pkg, t.Elem()) - if key == nil || value == nil { - return nil - } - return &ast.MapType{ - Key: key, - Value: value, - } - case *types.Chan: - dir := ast.ChanDir(t.Dir()) - if t.Dir() == types.SendRecv { - dir = ast.SEND | ast.RECV - } - value := TypeExpr(f, pkg, t.Elem()) - if value == nil { - return nil - } - return &ast.ChanType{ - Dir: dir, - Value: value, - } - case *types.Signature: - var params []*ast.Field - for i := 0; i < t.Params().Len(); i++ { - p := TypeExpr(f, pkg, t.Params().At(i).Type()) - if p == nil { - return nil - } - params = append(params, &ast.Field{ - Type: p, - Names: []*ast.Ident{ - { - Name: t.Params().At(i).Name(), - }, - }, - }) - } - var returns []*ast.Field - for i := 0; i < t.Results().Len(); i++ { - r := TypeExpr(f, pkg, t.Results().At(i).Type()) - if r == nil { - return nil - } - returns = append(returns, &ast.Field{ - Type: r, - }) - } - return &ast.FuncType{ - Params: &ast.FieldList{ - List: params, - }, - Results: &ast.FieldList{ - List: returns, - }, - } - case *types.Named: - if t.Obj().Pkg() == nil { - return ast.NewIdent(t.Obj().Name()) - } - if t.Obj().Pkg() == pkg { - return ast.NewIdent(t.Obj().Name()) - } - pkgName := t.Obj().Pkg().Name() - - // If the file already imports the package under another name, use that. - for _, cand := range f.Imports { - if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() { - if cand.Name != nil && cand.Name.Name != "" { - pkgName = cand.Name.Name - } - } - } - if pkgName == "." { - return ast.NewIdent(t.Obj().Name()) - } - return &ast.SelectorExpr{ - X: ast.NewIdent(pkgName), - Sel: ast.NewIdent(t.Obj().Name()), - } - case *types.Struct: - return ast.NewIdent(t.String()) - case *types.Interface: - return ast.NewIdent(t.String()) - default: - return nil - } -} - -// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable. -// Some examples: -// -// Basic Example: -// z := 1 -// y := z + x -// If x is undeclared, then this function would return `y := z + x`, so that we -// can insert `x := ` on the line before `y := z + x`. -// -// If stmt example: -// if z == 1 { -// } else if z == y {} -// If y is undeclared, then this function would return `if z == 1 {`, because we cannot -// insert a statement between an if and an else if statement. As a result, we need to find -// the top of the if chain to insert `y := ` before. -func StmtToInsertVarBefore(path []ast.Node) ast.Stmt { - enclosingIndex := -1 - for i, p := range path { - if _, ok := p.(ast.Stmt); ok { - enclosingIndex = i - break - } - } - if enclosingIndex == -1 { - return nil - } - enclosingStmt := path[enclosingIndex] - switch enclosingStmt.(type) { - case *ast.IfStmt: - // The enclosingStmt is inside of the if declaration, - // We need to check if we are in an else-if stmt and - // get the base if statement. - return baseIfStmt(path, enclosingIndex) - case *ast.CaseClause: - // Get the enclosing switch stmt if the enclosingStmt is - // inside of the case statement. - for i := enclosingIndex + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.SwitchStmt); ok { - return node - } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok { - return node - } - } - } - if len(path) <= enclosingIndex+1 { - return enclosingStmt.(ast.Stmt) - } - // Check if the enclosing statement is inside another node. - switch expr := path[enclosingIndex+1].(type) { - case *ast.IfStmt: - // Get the base if statement. - return baseIfStmt(path, enclosingIndex+1) - case *ast.ForStmt: - if expr.Init == enclosingStmt || expr.Post == enclosingStmt { - return expr - } - } - return enclosingStmt.(ast.Stmt) -} - -// baseIfStmt walks up the if/else-if chain until we get to -// the top of the current if chain. -func baseIfStmt(path []ast.Node, index int) ast.Stmt { - stmt := path[index] - for i := index + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt { - stmt = node - continue - } - break - } - return stmt.(ast.Stmt) -} - -// WalkASTWithParent walks the AST rooted at n. The semantics are -// similar to ast.Inspect except it does not call f(nil). -func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) { - var ancestors []ast.Node - ast.Inspect(n, func(n ast.Node) (recurse bool) { - if n == nil { - ancestors = ancestors[:len(ancestors)-1] - return false - } - - var parent ast.Node - if len(ancestors) > 0 { - parent = ancestors[len(ancestors)-1] - } - ancestors = append(ancestors, n) - return f(n, parent) - }) -} - -// MatchingIdents finds the names of all identifiers in 'node' that match any of the given types. -// 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within -// the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that -// is unrecognized. -func MatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]string { - - // Initialize matches to contain the variable types we are searching for. - matches := make(map[types.Type][]string) - for _, typ := range typs { - if typ == nil { - continue // TODO(adonovan): is this reachable? - } - matches[typ] = nil // create entry - } - - seen := map[types.Object]struct{}{} - ast.Inspect(node, func(n ast.Node) bool { - if n == nil { - return false - } - // Prevent circular definitions. If 'pos' is within an assignment statement, do not - // allow any identifiers in that assignment statement to be selected. Otherwise, - // we could do the following, where 'x' satisfies the type of 'f0': - // - // x := fakeStruct{f0: x} - // - if assign, ok := n.(*ast.AssignStmt); ok && pos > assign.Pos() && pos <= assign.End() { - return false - } - if n.End() > pos { - return n.Pos() <= pos - } - ident, ok := n.(*ast.Ident) - if !ok || ident.Name == "_" { - return true - } - obj := info.Defs[ident] - if obj == nil || obj.Type() == nil { - return true - } - if _, ok := obj.(*types.TypeName); ok { - return true - } - // Prevent duplicates in matches' values. - if _, ok = seen[obj]; ok { - return true - } - seen[obj] = struct{}{} - // Find the scope for the given position. Then, check whether the object - // exists within the scope. - innerScope := pkg.Scope().Innermost(pos) - if innerScope == nil { - return true - } - _, foundObj := innerScope.LookupParent(ident.Name, pos) - if foundObj != obj { - return true - } - // The object must match one of the types that we are searching for. - // TODO(adonovan): opt: use typeutil.Map? - if names, ok := matches[obj.Type()]; ok { - matches[obj.Type()] = append(names, ident.Name) - } else { - // If the object type does not exactly match - // any of the target types, greedily find the first - // target type that the object type can satisfy. - for typ := range matches { - if equivalentTypes(obj.Type(), typ) { - matches[typ] = append(matches[typ], ident.Name) - } - } - } - return true - }) - return matches -} - -func equivalentTypes(want, got types.Type) bool { - if types.Identical(want, got) { - return true - } - // Code segment to help check for untyped equality from (golang/go#32146). - if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 { - if lhs, ok := got.Underlying().(*types.Basic); ok { - return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType - } - } - return types.AssignableTo(want, got) -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index ba53cdcdd..a0dc0b5e2 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -44,12 +44,12 @@ func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { return out.Bytes(), err } -// IImportShallow decodes "shallow" types.Package data encoded by IExportShallow -// in the same executable. This function cannot import data from +// IImportShallow decodes "shallow" types.Package data encoded by +// IExportShallow in the same executable. This function cannot import data from // cmd/compile or gcexportdata.Write. -func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) { +func IImportShallow(fset *token.FileSet, getPackage GetPackageFunc, data []byte, path string, insert InsertType) (*types.Package, error) { const bundle = false - pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert) + pkgs, err := iimportCommon(fset, getPackage, data, bundle, path, insert) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index 448f903e8..be6dace15 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -85,7 +85,7 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { - pkgs, err := iimportCommon(fset, imports, data, false, path, nil) + pkgs, err := iimportCommon(fset, GetPackageFromMap(imports), data, false, path, nil) if err != nil { return 0, nil, err } @@ -94,10 +94,33 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] // IImportBundle imports a set of packages from the serialized package bundle. func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { - return iimportCommon(fset, imports, data, true, "", nil) + return iimportCommon(fset, GetPackageFromMap(imports), data, true, "", nil) } -func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { +// A GetPackageFunc is a function that gets the package with the given path +// from the importer state, creating it (with the specified name) if necessary. +// It is an abstraction of the map historically used to memoize package creation. +// +// Two calls with the same path must return the same package. +// +// If the given getPackage func returns nil, the import will fail. +type GetPackageFunc = func(path, name string) *types.Package + +// GetPackageFromMap returns a GetPackageFunc that retrieves packages from the +// given map of package path -> package. +// +// The resulting func may mutate m: if a requested package is not found, a new +// package will be inserted into m. +func GetPackageFromMap(m map[string]*types.Package) GetPackageFunc { + return func(path, name string) *types.Package { + if _, ok := m[path]; !ok { + m[path] = types.NewPackage(path, name) + } + return m[path] + } +} + +func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { const currentVersion = iexportVersionCurrent version := int64(-1) if !debug { @@ -195,10 +218,9 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data if pkgPath == "" { pkgPath = path } - pkg := imports[pkgPath] + pkg := getPackage(pkgPath, pkgName) if pkg == nil { - pkg = types.NewPackage(pkgPath, pkgName) - imports[pkgPath] = pkg + errorf("internal error: getPackage returned nil package for %s", pkgPath) } else if pkg.Name() != pkgName { errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) } diff --git a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go index a3fb2d4f2..7e638ec24 100644 --- a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go +++ b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go @@ -7,7 +7,9 @@ package tokeninternal import ( + "fmt" "go/token" + "sort" "sync" "unsafe" ) @@ -57,3 +59,93 @@ func GetLines(file *token.File) []int { panic("unexpected token.File size") } } + +// AddExistingFiles adds the specified files to the FileSet if they +// are not already present. It panics if any pair of files in the +// resulting FileSet would overlap. +func AddExistingFiles(fset *token.FileSet, files []*token.File) { + // Punch through the FileSet encapsulation. + type tokenFileSet struct { + // This type remained essentially consistent from go1.16 to go1.21. + mutex sync.RWMutex + base int + files []*token.File + _ *token.File // changed to atomic.Pointer[token.File] in go1.19 + } + + // If the size of token.FileSet changes, this will fail to compile. + const delta = int64(unsafe.Sizeof(tokenFileSet{})) - int64(unsafe.Sizeof(token.FileSet{})) + var _ [-delta * delta]int + + type uP = unsafe.Pointer + var ptr *tokenFileSet + *(*uP)(uP(&ptr)) = uP(fset) + ptr.mutex.Lock() + defer ptr.mutex.Unlock() + + // Merge and sort. + newFiles := append(ptr.files, files...) + sort.Slice(newFiles, func(i, j int) bool { + return newFiles[i].Base() < newFiles[j].Base() + }) + + // Reject overlapping files. + // Discard adjacent identical files. + out := newFiles[:0] + for i, file := range newFiles { + if i > 0 { + prev := newFiles[i-1] + if file == prev { + continue + } + if prev.Base()+prev.Size()+1 > file.Base() { + panic(fmt.Sprintf("file %s (%d-%d) overlaps with file %s (%d-%d)", + prev.Name(), prev.Base(), prev.Base()+prev.Size(), + file.Name(), file.Base(), file.Base()+file.Size())) + } + } + out = append(out, file) + } + newFiles = out + + ptr.files = newFiles + + // Advance FileSet.Base(). + if len(newFiles) > 0 { + last := newFiles[len(newFiles)-1] + newBase := last.Base() + last.Size() + 1 + if ptr.base < newBase { + ptr.base = newBase + } + } +} + +// FileSetFor returns a new FileSet containing a sequence of new Files with +// the same base, size, and line as the input files, for use in APIs that +// require a FileSet. +// +// Precondition: the input files must be non-overlapping, and sorted in order +// of their Base. +func FileSetFor(files ...*token.File) *token.FileSet { + fset := token.NewFileSet() + for _, f := range files { + f2 := fset.AddFile(f.Name(), f.Base(), f.Size()) + lines := GetLines(f) + f2.SetLines(lines) + } + return fset +} + +// CloneFileSet creates a new FileSet holding all files in fset. It does not +// create copies of the token.Files in fset: they are added to the resulting +// FileSet unmodified. +func CloneFileSet(fset *token.FileSet) *token.FileSet { + var files []*token.File + fset.Iterate(func(f *token.File) bool { + files = append(files, f) + return true + }) + newFileSet := token.NewFileSet() + AddExistingFiles(newFileSet, files) + return newFileSet +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 710f240eb..b270754dc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -448,8 +448,8 @@ github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.9 ## explicit; go 1.9 github.com/mattn/go-runewidth -# github.com/mattn/goveralls v0.0.9 -## explicit; go 1.11 +# github.com/mattn/goveralls v0.0.12 +## explicit; go 1.13 github.com/mattn/goveralls # github.com/matttproud/golang_protobuf_extensions v1.0.1 ## explicit @@ -805,7 +805,7 @@ golang.org/x/exp/slices # golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 ## explicit; go 1.18 golang.org/x/exp/typeparams -# golang.org/x/mod v0.9.0 +# golang.org/x/mod v0.10.0 ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile @@ -843,7 +843,7 @@ golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width -# golang.org/x/tools v0.7.0 +# golang.org/x/tools v0.8.0 ## explicit; go 1.18 golang.org/x/tools/cover golang.org/x/tools/go/analysis @@ -907,7 +907,6 @@ golang.org/x/tools/go/ssa/ssautil golang.org/x/tools/go/types/objectpath golang.org/x/tools/go/types/typeutil golang.org/x/tools/imports -golang.org/x/tools/internal/analysisinternal golang.org/x/tools/internal/event golang.org/x/tools/internal/event/core golang.org/x/tools/internal/event/keys From 9eeb6beaeb81b69ac6287445bbbc6ef41ef64063 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:34:57 +0200 Subject: [PATCH 17/31] gomod: Update github.com/prometheus/client_golang --- go.mod | 17 +- go.sum | 57 +- .../github.com/google/go-cmp/cmp/compare.go | 38 +- .../cmp/{export_unsafe.go => export.go} | 5 - .../google/go-cmp/cmp/export_panic.go | 16 - .../value/{pointer_unsafe.go => pointer.go} | 3 - .../cmp/internal/value/pointer_purego.go | 34 - .../github.com/google/go-cmp/cmp/options.go | 84 +- vendor/github.com/google/go-cmp/cmp/path.go | 46 +- .../google/go-cmp/cmp/report_reflect.go | 2 +- .../golang_protobuf_extensions/LICENSE | 201 --- .../golang_protobuf_extensions/NOTICE | 1 - .../pbutil/.gitignore | 1 - .../pbutil/Makefile | 7 - .../pbutil/decode.go | 75 - .../pbutil/encode.go | 46 - .../client_golang/prometheus/counter.go | 48 +- .../client_golang/prometheus/desc.go | 58 +- .../client_golang/prometheus/doc.go | 44 +- .../prometheus/expvar_collector.go | 2 +- .../client_golang/prometheus/gauge.go | 30 +- .../prometheus/go_collector_latest.go | 7 +- .../client_golang/prometheus/histogram.go | 221 ++- .../prometheus/internal/difflib.go | 2 +- .../client_golang/prometheus/labels.go | 100 ++ .../client_golang/prometheus/metric.go | 9 +- .../prometheus/process_collector_other.go | 4 +- .../prometheus/process_collector_wasip1.go | 26 + .../client_golang/prometheus/promhttp/http.go | 19 +- .../prometheus/promhttp/instrument_client.go | 26 +- .../prometheus/promhttp/instrument_server.go | 110 +- .../prometheus/promhttp/option.go | 38 +- .../client_golang/prometheus/registry.go | 19 +- .../client_golang/prometheus/summary.go | 72 +- .../prometheus/testutil/promlint/problem.go | 33 + .../prometheus/testutil/promlint/promlint.go | 312 +--- .../testutil/promlint/validation.go | 33 + .../validations/counter_validations.go | 40 + .../validations/generic_name_validations.go | 101 ++ .../promlint/validations/help_validations.go | 32 + .../validations/histogram_validations.go | 63 + .../testutil/promlint/validations/units.go | 118 ++ .../client_golang/prometheus/timer.go | 28 +- .../client_golang/prometheus/value.go | 61 +- .../client_golang/prometheus/vec.go | 95 +- .../client_golang/prometheus/vnext.go | 23 + .../client_golang/prometheus/wrap.go | 8 +- .../prometheus/client_model/go/metrics.pb.go | 1576 +++++++++++------ .../prometheus/common/expfmt/decode.go | 66 +- .../prometheus/common/expfmt/encode.go | 79 +- .../prometheus/common/expfmt/expfmt.go | 156 +- .../prometheus/common/expfmt/fuzz.go | 4 +- .../common/expfmt/openmetrics_create.go | 107 +- .../prometheus/common/expfmt/text_create.go | 121 +- .../prometheus/common/expfmt/text_parse.go | 16 +- .../bitbucket.org/ww/goautoneg/autoneg.go | 22 +- .../prometheus/common/model/alert.go | 4 +- .../prometheus/common/model/labels.go | 22 +- .../prometheus/common/model/metadata.go | 28 + .../prometheus/common/model/metric.go | 368 +++- .../prometheus/common/model/signature.go | 6 +- .../prometheus/common/model/silence.go | 2 +- .../prometheus/common/model/time.go | 89 +- .../prometheus/common/model/value.go | 262 ++- .../prometheus/common/model/value_float.go | 98 + .../common/model/value_histogram.go | 178 ++ .../prometheus/common/model/value_type.go | 83 + .../prometheus/procfs/.golangci.yml | 3 + .../prometheus/procfs/Makefile.common | 27 +- vendor/github.com/prometheus/procfs/README.md | 4 +- vendor/github.com/prometheus/procfs/arp.go | 6 +- .../github.com/prometheus/procfs/buddyinfo.go | 6 +- .../github.com/prometheus/procfs/cpuinfo.go | 53 +- .../procfs/cpuinfo_loong64.go} | 13 +- .../prometheus/procfs/cpuinfo_others.go | 4 +- vendor/github.com/prometheus/procfs/crypto.go | 7 +- vendor/github.com/prometheus/procfs/doc.go | 51 +- vendor/github.com/prometheus/procfs/fs.go | 11 +- .../prometheus/procfs/fs_statfs_notype.go | 23 + .../prometheus/procfs/fs_statfs_type.go | 33 + .../github.com/prometheus/procfs/fscache.go | 6 +- .../prometheus/procfs/internal/util/parse.go | 15 + vendor/github.com/prometheus/procfs/ipvs.go | 7 +- .../github.com/prometheus/procfs/loadavg.go | 4 +- vendor/github.com/prometheus/procfs/mdstat.go | 36 +- .../github.com/prometheus/procfs/meminfo.go | 4 +- .../github.com/prometheus/procfs/mountinfo.go | 10 +- .../prometheus/procfs/mountstats.go | 120 +- .../prometheus/procfs/net_conntrackstat.go | 91 +- .../prometheus/procfs/net_ip_socket.go | 32 +- .../prometheus/procfs/net_protocols.go | 4 +- .../github.com/prometheus/procfs/net_route.go | 143 ++ .../prometheus/procfs/net_sockstat.go | 9 +- .../prometheus/procfs/net_softnet.go | 79 +- .../github.com/prometheus/procfs/net_unix.go | 16 +- .../prometheus/procfs/net_wireless.go | 182 ++ .../github.com/prometheus/procfs/net_xfrm.go | 2 +- .../github.com/prometheus/procfs/netstat.go | 54 +- vendor/github.com/prometheus/procfs/proc.go | 37 +- .../prometheus/procfs/proc_cgroup.go | 6 +- .../prometheus/procfs/proc_cgroups.go | 8 +- .../prometheus/procfs/proc_fdinfo.go | 10 +- .../prometheus/procfs/proc_interrupts.go | 98 + .../prometheus/procfs/proc_limits.go | 4 +- .../github.com/prometheus/procfs/proc_maps.go | 24 +- .../prometheus/procfs/proc_netstat.go | 495 +++--- .../github.com/prometheus/procfs/proc_ns.go | 6 +- .../github.com/prometheus/procfs/proc_psi.go | 6 +- .../prometheus/procfs/proc_smaps.go | 4 +- .../github.com/prometheus/procfs/proc_snmp.go | 322 ++-- .../prometheus/procfs/proc_snmp6.go | 364 ++-- .../github.com/prometheus/procfs/proc_stat.go | 12 +- .../prometheus/procfs/proc_status.go | 59 +- .../github.com/prometheus/procfs/proc_sys.go | 2 +- vendor/github.com/prometheus/procfs/slab.go | 2 +- .../github.com/prometheus/procfs/softirqs.go | 24 +- vendor/github.com/prometheus/procfs/stat.go | 50 +- vendor/github.com/prometheus/procfs/swaps.go | 8 +- vendor/github.com/prometheus/procfs/thread.go | 80 + vendor/github.com/prometheus/procfs/vm.go | 6 +- .../github.com/prometheus/procfs/zoneinfo.go | 4 +- vendor/golang.org/x/net/http2/databuffer.go | 59 +- vendor/golang.org/x/net/http2/go111.go | 30 - vendor/golang.org/x/net/http2/go115.go | 27 - vendor/golang.org/x/net/http2/go118.go | 17 - vendor/golang.org/x/net/http2/not_go111.go | 21 - vendor/golang.org/x/net/http2/not_go115.go | 31 - vendor/golang.org/x/net/http2/not_go118.go | 17 - vendor/golang.org/x/net/http2/server.go | 24 +- vendor/golang.org/x/net/http2/transport.go | 33 +- vendor/golang.org/x/net/idna/go118.go | 1 - vendor/golang.org/x/net/idna/idna10.0.0.go | 1 - vendor/golang.org/x/net/idna/idna9.0.0.go | 1 - vendor/golang.org/x/net/idna/pre_go118.go | 1 - vendor/golang.org/x/net/idna/tables10.0.0.go | 1 - vendor/golang.org/x/net/idna/tables11.0.0.go | 1 - vendor/golang.org/x/net/idna/tables12.0.0.go | 1 - vendor/golang.org/x/net/idna/tables13.0.0.go | 1 - vendor/golang.org/x/net/idna/tables15.0.0.go | 1 - vendor/golang.org/x/net/idna/tables9.0.0.go | 1 - vendor/golang.org/x/net/idna/trie12.0.0.go | 1 - vendor/golang.org/x/net/idna/trie13.0.0.go | 1 - vendor/golang.org/x/sys/unix/mkerrors.sh | 37 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 54 + .../x/sys/unix/zsyscall_openbsd_386.go | 2 - .../x/sys/unix/zsyscall_openbsd_amd64.go | 2 - .../x/sys/unix/zsyscall_openbsd_arm.go | 2 - .../x/sys/unix/zsyscall_openbsd_arm64.go | 2 - .../x/sys/unix/zsyscall_openbsd_mips64.go | 2 - .../x/sys/unix/zsyscall_openbsd_ppc64.go | 2 - .../x/sys/unix/zsyscall_openbsd_riscv64.go | 2 - .../x/sys/windows/syscall_windows.go | 1 + .../x/sys/windows/zsyscall_windows.go | 9 + .../encoding/protodelim/protodelim.go | 160 ++ vendor/modules.txt | 31 +- 155 files changed, 5798 insertions(+), 3167 deletions(-) rename vendor/github.com/google/go-cmp/cmp/{export_unsafe.go => export.go} (94%) delete mode 100644 vendor/github.com/google/go-cmp/cmp/export_panic.go rename vendor/github.com/google/go-cmp/cmp/internal/value/{pointer_unsafe.go => pointer.go} (95%) delete mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/process_collector_wasip1.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/problem.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validation.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/counter_validations.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/generic_name_validations.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/help_validations.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/histogram_validations.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/units.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/vnext.go create mode 100644 vendor/github.com/prometheus/common/model/metadata.go create mode 100644 vendor/github.com/prometheus/common/model/value_float.go create mode 100644 vendor/github.com/prometheus/common/model/value_histogram.go create mode 100644 vendor/github.com/prometheus/common/model/value_type.go rename vendor/github.com/{matttproud/golang_protobuf_extensions/pbutil/doc.go => prometheus/procfs/cpuinfo_loong64.go} (73%) create mode 100644 vendor/github.com/prometheus/procfs/fs_statfs_notype.go create mode 100644 vendor/github.com/prometheus/procfs/fs_statfs_type.go create mode 100644 vendor/github.com/prometheus/procfs/net_route.go create mode 100644 vendor/github.com/prometheus/procfs/net_wireless.go create mode 100644 vendor/github.com/prometheus/procfs/proc_interrupts.go create mode 100644 vendor/github.com/prometheus/procfs/thread.go delete mode 100644 vendor/golang.org/x/net/http2/go111.go delete mode 100644 vendor/golang.org/x/net/http2/go115.go delete mode 100644 vendor/golang.org/x/net/http2/go118.go delete mode 100644 vendor/golang.org/x/net/http2/not_go111.go delete mode 100644 vendor/golang.org/x/net/http2/not_go115.go delete mode 100644 vendor/golang.org/x/net/http2/not_go118.go create mode 100644 vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go diff --git a/go.mod b/go.mod index af873ea1d..0b7c15963 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 - github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/client_golang v1.19.0 github.com/rs/xid v1.2.1 github.com/rs/zerolog v1.17.2 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 @@ -107,7 +107,7 @@ require ( github.com/golangci/misspell v0.4.0 // indirect github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect @@ -144,7 +144,6 @@ require ( github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect github.com/mgechev/revive v1.2.5 // indirect github.com/minio/md5-simd v1.1.0 // indirect @@ -163,9 +162,9 @@ require ( github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/polyfloyd/go-errorlint v1.1.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/quasilyte/go-ruleguard v0.3.19 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect @@ -209,13 +208,13 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.18.1 // indirect - golang.org/x/crypto v0.17.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.20.0 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/tools v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect diff --git a/go.sum b/go.sum index bd0166110..5f9513da0 100644 --- a/go.sum +++ b/go.sum @@ -180,7 +180,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 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-kivik/couchdb/v3 v3.2.6 h1:IzoAH5K7jsY1BFNibtdjAoPXRmm3rdQKJGjDMzXMvok= github.com/go-kivik/couchdb/v3 v3.2.6/go.mod h1:tUgf+ftTYkkNPyHskJW2O+6I1NUQvg7ucooVvhPQcxg= github.com/go-kivik/kivik/v3 v3.0.1/go.mod h1:7tmQDvkta/pcijpUjLMsQ9HJUELiKD5zm6jQ3Gb9cxE= @@ -192,7 +191,6 @@ github.com/go-kivik/kiviktest/v3 v3.0.3/go.mod h1:sqsz3M2sJxTxAUdOj+2SU21y4phcpY 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-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-pg/pg v6.14.5+incompatible h1:Tc74MTCCIVd8sAJshYHqutcHhO64/EBHBTydzCGt3Js= @@ -295,8 +293,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= @@ -407,8 +405,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -450,7 +448,6 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/goveralls v0.0.12 h1:PEEeF0k1SsTjOBQ8FOmrOAoCu4ytuMaWCnWe94zxbCg= github.com/mattn/goveralls v0.0.12/go.mod h1:44ImGEUfmqH8bBtaMrYKsM65LXfNLWmwaxFGjZwgMSQ= -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/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= @@ -482,8 +479,6 @@ github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81 github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/exhaustive v0.9.5 h1:TzssWan6orBiLYVqewCG8faud9qlFntJE30ACpzmGME= github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= @@ -534,27 +529,27 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn 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.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= 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/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= 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/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= 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/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc= github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= @@ -564,8 +559,8 @@ github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:r github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.17.2 h1:RMRHFw2+wF7LO0QqtELQwo8hqSmqISyCJeFeAAuWcRo= @@ -717,8 +712,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 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= @@ -809,8 +804,6 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/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/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -818,8 +811,8 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 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= @@ -831,9 +824,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= 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= @@ -902,7 +894,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -917,8 +908,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1145,8 +1136,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks 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/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go index 087320da7..0f5b8a48c 100644 --- a/vendor/github.com/google/go-cmp/cmp/compare.go +++ b/vendor/github.com/google/go-cmp/cmp/compare.go @@ -5,7 +5,7 @@ // Package cmp determines equality of values. // // This package is intended to be a more powerful and safer alternative to -// reflect.DeepEqual for comparing whether two values are semantically equal. +// [reflect.DeepEqual] for comparing whether two values are semantically equal. // It is intended to only be used in tests, as performance is not a goal and // it may panic if it cannot compare the values. Its propensity towards // panicking means that its unsuitable for production environments where a @@ -18,16 +18,17 @@ // For example, an equality function may report floats as equal so long as // they are within some tolerance of each other. // -// - Types with an Equal method may use that method to determine equality. -// This allows package authors to determine the equality operation -// for the types that they define. +// - Types with an Equal method (e.g., [time.Time.Equal]) may use that method +// to determine equality. This allows package authors to determine +// the equality operation for the types that they define. // // - If no custom equality functions are used and no Equal method is defined, // equality is determined by recursively comparing the primitive kinds on -// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, +// both values, much like [reflect.DeepEqual]. Unlike [reflect.DeepEqual], // unexported fields are not compared by default; they result in panics -// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported) -// or explicitly compared using the Exporter option. +// unless suppressed by using an [Ignore] option +// (see [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]) +// or explicitly compared using the [Exporter] option. package cmp import ( @@ -45,14 +46,14 @@ import ( // Equal reports whether x and y are equal by recursively applying the // following rules in the given order to x and y and all of their sub-values: // -// - Let S be the set of all Ignore, Transformer, and Comparer options that +// - Let S be the set of all [Ignore], [Transformer], and [Comparer] options that // remain after applying all path filters, value filters, and type filters. -// If at least one Ignore exists in S, then the comparison is ignored. -// If the number of Transformer and Comparer options in S is non-zero, +// If at least one [Ignore] exists in S, then the comparison is ignored. +// If the number of [Transformer] and [Comparer] options in S is non-zero, // then Equal panics because it is ambiguous which option to use. -// If S contains a single Transformer, then use that to transform +// If S contains a single [Transformer], then use that to transform // the current values and recursively call Equal on the output values. -// If S contains a single Comparer, then use that to compare the current values. +// If S contains a single [Comparer], then use that to compare the current values. // Otherwise, evaluation proceeds to the next rule. // // - If the values have an Equal method of the form "(T) Equal(T) bool" or @@ -66,21 +67,22 @@ import ( // Functions are only equal if they are both nil, otherwise they are unequal. // // Structs are equal if recursively calling Equal on all fields report equal. -// If a struct contains unexported fields, Equal panics unless an Ignore option -// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option -// explicitly permits comparing the unexported field. +// If a struct contains unexported fields, Equal panics unless an [Ignore] option +// (e.g., [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported]) ignores that field +// or the [Exporter] option explicitly permits comparing the unexported field. // // Slices are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored slice or array elements report equal. // Empty non-nil slices and nil slices are not equal; to equate empty slices, -// consider using cmpopts.EquateEmpty. +// consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty]. // // Maps are equal if they are both nil or both non-nil, where recursively // calling Equal on all non-ignored map entries report equal. // Map keys are equal according to the == operator. -// To use custom comparisons for map keys, consider using cmpopts.SortMaps. +// To use custom comparisons for map keys, consider using +// [github.com/google/go-cmp/cmp/cmpopts.SortMaps]. // Empty non-nil maps and nil maps are not equal; to equate empty maps, -// consider using cmpopts.EquateEmpty. +// consider using [github.com/google/go-cmp/cmp/cmpopts.EquateEmpty]. // // Pointers and interfaces are equal if they are both nil or both non-nil, // where they have the same underlying concrete type and recursively diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export.go similarity index 94% rename from vendor/github.com/google/go-cmp/cmp/export_unsafe.go rename to vendor/github.com/google/go-cmp/cmp/export.go index e2c0f74e8..29f82fe6b 100644 --- a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/export.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !purego -// +build !purego - package cmp import ( @@ -12,8 +9,6 @@ import ( "unsafe" ) -const supportExporters = true - // retrieveUnexportedField uses unsafe to forcibly retrieve any field from // a struct such that the value has read-write permissions. // diff --git a/vendor/github.com/google/go-cmp/cmp/export_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go deleted file mode 100644 index ae851fe53..000000000 --- a/vendor/github.com/google/go-cmp/cmp/export_panic.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build purego -// +build purego - -package cmp - -import "reflect" - -const supportExporters = false - -func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value { - panic("no support for forcibly accessing unexported fields") -} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go similarity index 95% rename from vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go rename to vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go index 16e6860af..e5dfff69a 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !purego -// +build !purego - package value import ( diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go deleted file mode 100644 index 1a71bfcbd..000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build purego -// +build purego - -package value - -import "reflect" - -// Pointer is an opaque typed pointer and is guaranteed to be comparable. -type Pointer struct { - p uintptr - t reflect.Type -} - -// PointerOf returns a Pointer from v, which must be a -// reflect.Ptr, reflect.Slice, or reflect.Map. -func PointerOf(v reflect.Value) Pointer { - // NOTE: Storing a pointer as an uintptr is technically incorrect as it - // assumes that the GC implementation does not use a moving collector. - return Pointer{v.Pointer(), v.Type()} -} - -// IsNil reports whether the pointer is nil. -func (p Pointer) IsNil() bool { - return p.p == 0 -} - -// Uintptr returns the pointer as a uintptr. -func (p Pointer) Uintptr() uintptr { - return p.p -} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go index 1f9ca9c48..754496f3b 100644 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -13,15 +13,15 @@ import ( "github.com/google/go-cmp/cmp/internal/function" ) -// Option configures for specific behavior of Equal and Diff. In particular, -// the fundamental Option functions (Ignore, Transformer, and Comparer), +// Option configures for specific behavior of [Equal] and [Diff]. In particular, +// the fundamental Option functions ([Ignore], [Transformer], and [Comparer]), // configure how equality is determined. // -// The fundamental options may be composed with filters (FilterPath and -// FilterValues) to control the scope over which they are applied. +// The fundamental options may be composed with filters ([FilterPath] and +// [FilterValues]) to control the scope over which they are applied. // -// The cmp/cmpopts package provides helper functions for creating options that -// may be used with Equal and Diff. +// The [github.com/google/go-cmp/cmp/cmpopts] package provides helper functions +// for creating options that may be used with [Equal] and [Diff]. type Option interface { // filter applies all filters and returns the option that remains. // Each option may only read s.curPath and call s.callTTBFunc. @@ -56,9 +56,9 @@ type core struct{} func (core) isCore() {} -// Options is a list of Option values that also satisfies the Option interface. +// Options is a list of [Option] values that also satisfies the [Option] interface. // Helper comparison packages may return an Options value when packing multiple -// Option values into a single Option. When this package processes an Options, +// [Option] values into a single [Option]. When this package processes an Options, // it will be implicitly expanded into a flat list. // // Applying a filter on an Options is equivalent to applying that same filter @@ -105,16 +105,16 @@ func (opts Options) String() string { return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) } -// FilterPath returns a new Option where opt is only evaluated if filter f -// returns true for the current Path in the value tree. +// FilterPath returns a new [Option] where opt is only evaluated if filter f +// returns true for the current [Path] in the value tree. // // This filter is called even if a slice element or map entry is missing and // provides an opportunity to ignore such cases. The filter function must be // symmetric such that the filter result is identical regardless of whether the // missing value is from x or y. // -// The option passed in may be an Ignore, Transformer, Comparer, Options, or -// a previously filtered Option. +// The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or +// a previously filtered [Option]. func FilterPath(f func(Path) bool, opt Option) Option { if f == nil { panic("invalid path filter function") @@ -142,7 +142,7 @@ func (f pathFilter) String() string { return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) } -// FilterValues returns a new Option where opt is only evaluated if filter f, +// FilterValues returns a new [Option] where opt is only evaluated if filter f, // which is a function of the form "func(T, T) bool", returns true for the // current pair of values being compared. If either value is invalid or // the type of the values is not assignable to T, then this filter implicitly @@ -154,8 +154,8 @@ func (f pathFilter) String() string { // If T is an interface, it is possible that f is called with two values with // different concrete types that both implement T. // -// The option passed in may be an Ignore, Transformer, Comparer, Options, or -// a previously filtered Option. +// The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or +// a previously filtered [Option]. func FilterValues(f interface{}, opt Option) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { @@ -192,9 +192,9 @@ func (f valuesFilter) String() string { return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) } -// Ignore is an Option that causes all comparisons to be ignored. -// This value is intended to be combined with FilterPath or FilterValues. -// It is an error to pass an unfiltered Ignore option to Equal. +// Ignore is an [Option] that causes all comparisons to be ignored. +// This value is intended to be combined with [FilterPath] or [FilterValues]. +// It is an error to pass an unfiltered Ignore option to [Equal]. func Ignore() Option { return ignore{} } type ignore struct{ core } @@ -234,6 +234,8 @@ func (validator) apply(s *state, vx, vy reflect.Value) { name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType if _, ok := reflect.New(t).Interface().(error); ok { help = "consider using cmpopts.EquateErrors to compare error values" + } else if t.Comparable() { + help = "consider using cmpopts.EquateComparable to compare comparable Go types" } } else { // Unnamed type with unexported fields. Derive PkgPath from field. @@ -254,7 +256,7 @@ const identRx = `[_\p{L}][_\p{L}\p{N}]*` var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) -// Transformer returns an Option that applies a transformation function that +// Transformer returns an [Option] that applies a transformation function that // converts values of a certain type into that of another. // // The transformer f must be a function "func(T) R" that converts values of @@ -265,13 +267,14 @@ var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) // same transform to the output of itself (e.g., in the case where the // input and output types are the same), an implicit filter is added such that // a transformer is applicable only if that exact transformer is not already -// in the tail of the Path since the last non-Transform step. +// in the tail of the [Path] since the last non-[Transform] step. // For situations where the implicit filter is still insufficient, -// consider using cmpopts.AcyclicTransformer, which adds a filter -// to prevent the transformer from being recursively applied upon itself. +// consider using [github.com/google/go-cmp/cmp/cmpopts.AcyclicTransformer], +// which adds a filter to prevent the transformer from +// being recursively applied upon itself. // -// The name is a user provided label that is used as the Transform.Name in the -// transformation PathStep (and eventually shown in the Diff output). +// The name is a user provided label that is used as the [Transform.Name] in the +// transformation [PathStep] (and eventually shown in the [Diff] output). // The name must be a valid identifier or qualified identifier in Go syntax. // If empty, an arbitrary name is used. func Transformer(name string, f interface{}) Option { @@ -329,7 +332,7 @@ func (tr transformer) String() string { return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) } -// Comparer returns an Option that determines whether two values are equal +// Comparer returns an [Option] that determines whether two values are equal // to each other. // // The comparer f must be a function "func(T, T) bool" and is implicitly @@ -377,35 +380,32 @@ func (cm comparer) String() string { return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) } -// Exporter returns an Option that specifies whether Equal is allowed to +// Exporter returns an [Option] that specifies whether [Equal] is allowed to // introspect into the unexported fields of certain struct types. // // Users of this option must understand that comparing on unexported fields // from external packages is not safe since changes in the internal -// implementation of some external package may cause the result of Equal +// implementation of some external package may cause the result of [Equal] // to unexpectedly change. However, it may be valid to use this option on types // defined in an internal package where the semantic meaning of an unexported // field is in the control of the user. // -// In many cases, a custom Comparer should be used instead that defines +// In many cases, a custom [Comparer] should be used instead that defines // equality as a function of the public API of a type rather than the underlying // unexported implementation. // -// For example, the reflect.Type documentation defines equality to be determined +// For example, the [reflect.Type] documentation defines equality to be determined // by the == operator on the interface (essentially performing a shallow pointer -// comparison) and most attempts to compare *regexp.Regexp types are interested +// comparison) and most attempts to compare *[regexp.Regexp] types are interested // in only checking that the regular expression strings are equal. -// Both of these are accomplished using Comparers: +// Both of these are accomplished using [Comparer] options: // // Comparer(func(x, y reflect.Type) bool { return x == y }) // Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) // -// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore -// all unexported fields on specified struct types. +// In other cases, the [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported] +// option can be used to ignore all unexported fields on specified struct types. func Exporter(f func(reflect.Type) bool) Option { - if !supportExporters { - panic("Exporter is not supported on purego builds") - } return exporter(f) } @@ -415,10 +415,10 @@ func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableO panic("not implemented") } -// AllowUnexported returns an Options that allows Equal to forcibly introspect +// AllowUnexported returns an [Option] that allows [Equal] to forcibly introspect // unexported fields of the specified struct types. // -// See Exporter for the proper use of this option. +// See [Exporter] for the proper use of this option. func AllowUnexported(types ...interface{}) Option { m := make(map[reflect.Type]bool) for _, typ := range types { @@ -432,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option { } // Result represents the comparison result for a single node and -// is provided by cmp when calling Report (see Reporter). +// is provided by cmp when calling Report (see [Reporter]). type Result struct { _ [0]func() // Make Result incomparable flags resultFlags @@ -445,7 +445,7 @@ func (r Result) Equal() bool { } // ByIgnore reports whether the node is equal because it was ignored. -// This never reports true if Equal reports false. +// This never reports true if [Result.Equal] reports false. func (r Result) ByIgnore() bool { return r.flags&reportByIgnore != 0 } @@ -455,7 +455,7 @@ func (r Result) ByMethod() bool { return r.flags&reportByMethod != 0 } -// ByFunc reports whether a Comparer function determined equality. +// ByFunc reports whether a [Comparer] function determined equality. func (r Result) ByFunc() bool { return r.flags&reportByFunc != 0 } @@ -478,7 +478,7 @@ const ( reportByCycle ) -// Reporter is an Option that can be passed to Equal. When Equal traverses +// Reporter is an [Option] that can be passed to [Equal]. When [Equal] traverses // the value trees, it calls PushStep as it descends into each node in the // tree and PopStep as it ascend out of the node. The leaves of the tree are // either compared (determined to be equal or not equal) or ignored and reported diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go index a0a588502..c3c145642 100644 --- a/vendor/github.com/google/go-cmp/cmp/path.go +++ b/vendor/github.com/google/go-cmp/cmp/path.go @@ -14,9 +14,9 @@ import ( "github.com/google/go-cmp/cmp/internal/value" ) -// Path is a list of PathSteps describing the sequence of operations to get +// Path is a list of [PathStep] describing the sequence of operations to get // from some root type to the current position in the value tree. -// The first Path element is always an operation-less PathStep that exists +// The first Path element is always an operation-less [PathStep] that exists // simply to identify the initial type. // // When traversing structs with embedded structs, the embedded struct will @@ -29,8 +29,13 @@ type Path []PathStep // a value's tree structure. Users of this package never need to implement // these types as values of this type will be returned by this package. // -// Implementations of this interface are -// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. +// Implementations of this interface: +// - [StructField] +// - [SliceIndex] +// - [MapIndex] +// - [Indirect] +// - [TypeAssertion] +// - [Transform] type PathStep interface { String() string @@ -70,8 +75,9 @@ func (pa *Path) pop() { *pa = (*pa)[:len(*pa)-1] } -// Last returns the last PathStep in the Path. -// If the path is empty, this returns a non-nil PathStep that reports a nil Type. +// Last returns the last [PathStep] in the Path. +// If the path is empty, this returns a non-nil [PathStep] +// that reports a nil [PathStep.Type]. func (pa Path) Last() PathStep { return pa.Index(-1) } @@ -79,7 +85,8 @@ func (pa Path) Last() PathStep { // Index returns the ith step in the Path and supports negative indexing. // A negative index starts counting from the tail of the Path such that -1 // refers to the last step, -2 refers to the second-to-last step, and so on. -// If index is invalid, this returns a non-nil PathStep that reports a nil Type. +// If index is invalid, this returns a non-nil [PathStep] +// that reports a nil [PathStep.Type]. func (pa Path) Index(i int) PathStep { if i < 0 { i = len(pa) + i @@ -168,7 +175,8 @@ func (ps pathStep) String() string { return fmt.Sprintf("{%s}", s) } -// StructField represents a struct field access on a field called Name. +// StructField is a [PathStep] that represents a struct field access +// on a field called [StructField.Name]. type StructField struct{ *structField } type structField struct { pathStep @@ -204,10 +212,11 @@ func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } func (sf StructField) Name() string { return sf.name } // Index is the index of the field in the parent struct type. -// See reflect.Type.Field. +// See [reflect.Type.Field]. func (sf StructField) Index() int { return sf.idx } -// SliceIndex is an index operation on a slice or array at some index Key. +// SliceIndex is a [PathStep] that represents an index operation on +// a slice or array at some index [SliceIndex.Key]. type SliceIndex struct{ *sliceIndex } type sliceIndex struct { pathStep @@ -247,12 +256,12 @@ func (si SliceIndex) Key() int { // all of the indexes to be shifted. If an index is -1, then that // indicates that the element does not exist in the associated slice. // -// Key is guaranteed to return -1 if and only if the indexes returned -// by SplitKeys are not the same. SplitKeys will never return -1 for +// [SliceIndex.Key] is guaranteed to return -1 if and only if the indexes +// returned by SplitKeys are not the same. SplitKeys will never return -1 for // both indexes. func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } -// MapIndex is an index operation on a map at some index Key. +// MapIndex is a [PathStep] that represents an index operation on a map at some index Key. type MapIndex struct{ *mapIndex } type mapIndex struct { pathStep @@ -266,7 +275,7 @@ func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", // Key is the value of the map key. func (mi MapIndex) Key() reflect.Value { return mi.key } -// Indirect represents pointer indirection on the parent type. +// Indirect is a [PathStep] that represents pointer indirection on the parent type. type Indirect struct{ *indirect } type indirect struct { pathStep @@ -276,7 +285,7 @@ func (in Indirect) Type() reflect.Type { return in.typ } func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } func (in Indirect) String() string { return "*" } -// TypeAssertion represents a type assertion on an interface. +// TypeAssertion is a [PathStep] that represents a type assertion on an interface. type TypeAssertion struct{ *typeAssertion } type typeAssertion struct { pathStep @@ -286,7 +295,8 @@ func (ta TypeAssertion) Type() reflect.Type { return ta.typ } func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } -// Transform is a transformation from the parent type to the current type. +// Transform is a [PathStep] that represents a transformation +// from the parent type to the current type. type Transform struct{ *transform } type transform struct { pathStep @@ -297,13 +307,13 @@ func (tf Transform) Type() reflect.Type { return tf.typ } func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } -// Name is the name of the Transformer. +// Name is the name of the [Transformer]. func (tf Transform) Name() string { return tf.trans.name } // Func is the function pointer to the transformer function. func (tf Transform) Func() reflect.Value { return tf.trans.fnc } -// Option returns the originally constructed Transformer option. +// Option returns the originally constructed [Transformer] option. // The == operator can be used to detect the exact option used. func (tf Transform) Option() Option { return tf.trans } diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go index 2ab41fad3..e39f42284 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -199,7 +199,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, break } sf := t.Field(i) - if supportExporters && !isExported(sf.Name) { + if !isExported(sf.Name) { vv = retrieveUnexportedField(v, sf, true) } s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE b/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE deleted file mode 100644 index 8dada3eda..000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE b/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE deleted file mode 100644 index 5d8cb5b72..000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE +++ /dev/null @@ -1 +0,0 @@ -Copyright 2012 Matt T. Proud (matt.proud@gmail.com) diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore deleted file mode 100644 index e16fb946b..000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cover.dat diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile deleted file mode 100644 index 81be21437..000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: - -cover: - go test -cover -v -coverprofile=cover.dat ./... - go tool cover -func cover.dat - -.PHONY: cover diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go deleted file mode 100644 index 258c0636a..000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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) -} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go deleted file mode 100644 index 8fb59ad22..000000000 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go +++ /dev/null @@ -1,46 +0,0 @@ -// 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 -} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go index a912b75a0..4ce84e7a8 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go @@ -20,6 +20,7 @@ import ( "time" dto "github.com/prometheus/client_model/go" + "google.golang.org/protobuf/types/known/timestamppb" ) // Counter is a Metric that represents a single numerical value that only ever @@ -59,6 +60,18 @@ type ExemplarAdder interface { // CounterOpts is an alias for Opts. See there for doc comments. type CounterOpts Opts +// CounterVecOpts bundles the options to create a CounterVec metric. +// It is mandatory to set CounterOpts, see there for mandatory fields. VariableLabels +// is optional and can safely be left to its default value. +type CounterVecOpts struct { + CounterOpts + + // VariableLabels are used to partition the metric vector by the given set + // of labels. Each label value will be constrained with the optional Constraint + // function, if provided. + VariableLabels ConstrainableLabels +} + // NewCounter creates a new Counter based on the provided CounterOpts. // // The returned implementation also implements ExemplarAdder. It is safe to @@ -78,8 +91,12 @@ func NewCounter(opts CounterOpts) Counter { nil, opts.ConstLabels, ) - result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: time.Now} + if opts.now == nil { + opts.now = time.Now + } + result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: opts.now} result.init(result) // Init self-collection. + result.createdTs = timestamppb.New(opts.now()) return result } @@ -94,10 +111,12 @@ type counter struct { selfCollector desc *Desc + createdTs *timestamppb.Timestamp labelPairs []*dto.LabelPair exemplar atomic.Value // Containing nil or a *dto.Exemplar. - now func() time.Time // To mock out time.Now() for testing. + // now is for testing purposes, by default it's time.Now. + now func() time.Time } func (c *counter) Desc() *Desc { @@ -147,8 +166,7 @@ func (c *counter) Write(out *dto.Metric) error { exemplar = e.(*dto.Exemplar) } val := c.get() - - return populateMetric(CounterValue, val, c.labelPairs, exemplar, out) + return populateMetric(CounterValue, val, c.labelPairs, exemplar, out, c.createdTs) } func (c *counter) updateExemplar(v float64, l Labels) { @@ -174,19 +192,31 @@ type CounterVec struct { // 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( + return V2.NewCounterVec(CounterVecOpts{ + CounterOpts: opts, + VariableLabels: UnconstrainedLabels(labelNames), + }) +} + +// NewCounterVec creates a new CounterVec based on the provided CounterVecOpts. +func (v2) NewCounterVec(opts CounterVecOpts) *CounterVec { + desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, - labelNames, + opts.VariableLabels, opts.ConstLabels, ) + if opts.now == nil { + opts.now = time.Now + } return &CounterVec{ MetricVec: NewMetricVec(desc, func(lvs ...string) Metric { - if len(lvs) != len(desc.variableLabels) { - panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) + if len(lvs) != len(desc.variableLabels.names) { + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, lvs)) } - result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now} + result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: opts.now} result.init(result) // Init self-collection. + result.createdTs = timestamppb.New(opts.now()) return result }), } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 8bc5e44e2..68ffe3c24 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -14,20 +14,16 @@ package prometheus import ( - "errors" "fmt" "sort" "strings" "github.com/cespare/xxhash/v2" - - "github.com/prometheus/client_golang/prometheus/internal" - - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" + dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/model" + "google.golang.org/protobuf/proto" - dto "github.com/prometheus/client_model/go" + "github.com/prometheus/client_golang/prometheus/internal" ) // Desc is the descriptor used by every Prometheus Metric. It is essentially @@ -54,9 +50,9 @@ type Desc struct { // constLabelPairs contains precalculated DTO label pairs based on // the constant labels. constLabelPairs []*dto.LabelPair - // variableLabels contains names of labels for which the metric - // maintains variable values. - variableLabels []string + // variableLabels contains names of labels and normalization function for + // which the metric maintains variable values. + variableLabels *compiledLabels // id is a hash of the values of the ConstLabels and fqName. This // must be unique among all registered descriptors and can therefore be // used as an identifier of the descriptor. @@ -80,10 +76,24 @@ type Desc struct { // For constLabels, the label values are constant. Therefore, they are fully // specified in the Desc. See the Collector example for a usage pattern. func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc { + return V2.NewDesc(fqName, help, UnconstrainedLabels(variableLabels), constLabels) +} + +// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc +// and will be reported on registration time. variableLabels and constLabels can +// be nil if no such labels should be set. fqName must not be empty. +// +// variableLabels only contain the label names and normalization functions. Their +// label values are variable and therefore not part of the Desc. (They are managed +// within the Metric.) +// +// For constLabels, the label values are constant. Therefore, they are fully +// specified in the Desc. See the Collector example for a usage pattern. +func (v2) NewDesc(fqName, help string, variableLabels ConstrainableLabels, constLabels Labels) *Desc { d := &Desc{ fqName: fqName, help: help, - variableLabels: variableLabels, + variableLabels: variableLabels.compile(), } if !model.IsValidMetricName(model.LabelValue(fqName)) { d.err = fmt.Errorf("%q is not a valid metric name", fqName) @@ -93,7 +103,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // their sorted label names) plus the fqName (at position 0). labelValues := make([]string, 1, len(constLabels)+1) labelValues[0] = fqName - labelNames := make([]string, 0, len(constLabels)+len(variableLabels)) + labelNames := make([]string, 0, len(constLabels)+len(d.variableLabels.names)) labelNameSet := map[string]struct{}{} // First add only the const label names and sort them... for labelName := range constLabels { @@ -118,16 +128,16 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // Now add the variable label names, but prefix them with something that // cannot be in a regular label name. That prevents matching the label // dimension with a different mix between preset and variable labels. - for _, labelName := range variableLabels { - if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) + for _, label := range d.variableLabels.names { + if !checkLabelName(label) { + d.err = fmt.Errorf("%q is not a valid label name for metric %q", label, fqName) return d } - labelNames = append(labelNames, "$"+labelName) - labelNameSet[labelName] = struct{}{} + labelNames = append(labelNames, "$"+label) + labelNameSet[label] = struct{}{} } if len(labelNames) != len(labelNameSet) { - d.err = errors.New("duplicate label names") + d.err = fmt.Errorf("duplicate label names in constant and variable labels for metric %q", fqName) return d } @@ -179,11 +189,19 @@ func (d *Desc) String() string { fmt.Sprintf("%s=%q", lp.GetName(), lp.GetValue()), ) } + vlStrings := make([]string, 0, len(d.variableLabels.names)) + for _, vl := range d.variableLabels.names { + if fn, ok := d.variableLabels.labelConstraints[vl]; ok && fn != nil { + vlStrings = append(vlStrings, fmt.Sprintf("c(%s)", vl)) + } else { + vlStrings = append(vlStrings, vl) + } + } return fmt.Sprintf( - "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: %v}", + "Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: {%s}}", d.fqName, d.help, strings.Join(lpStrings, ","), - d.variableLabels, + strings.Join(vlStrings, ","), ) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go index 811072cbd..962608f02 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go @@ -37,35 +37,35 @@ // // type metrics struct { // cpuTemp prometheus.Gauge -// hdFailures *prometheus.CounterVec +// hdFailures *prometheus.CounterVec // } // // func NewMetrics(reg prometheus.Registerer) *metrics { -// m := &metrics{ -// cpuTemp: prometheus.NewGauge(prometheus.GaugeOpts{ -// Name: "cpu_temperature_celsius", -// Help: "Current temperature of the CPU.", -// }), -// hdFailures: prometheus.NewCounterVec( -// prometheus.CounterOpts{ -// Name: "hd_errors_total", -// Help: "Number of hard-disk errors.", -// }, -// []string{"device"}, -// ), -// } -// reg.MustRegister(m.cpuTemp) -// reg.MustRegister(m.hdFailures) -// return m +// m := &metrics{ +// cpuTemp: prometheus.NewGauge(prometheus.GaugeOpts{ +// Name: "cpu_temperature_celsius", +// Help: "Current temperature of the CPU.", +// }), +// hdFailures: prometheus.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "hd_errors_total", +// Help: "Number of hard-disk errors.", +// }, +// []string{"device"}, +// ), +// } +// reg.MustRegister(m.cpuTemp) +// reg.MustRegister(m.hdFailures) +// return m // } // // func main() { -// // Create a non-global registry. -// reg := prometheus.NewRegistry() +// // Create a non-global registry. +// reg := prometheus.NewRegistry() // -// // Create new metrics and register them using the custom registry. -// m := NewMetrics(reg) -// // Set values for the new created metrics. +// // Create new metrics and register them using the custom registry. +// m := NewMetrics(reg) +// // Set values for the new created metrics. // m.cpuTemp.Set(65.3) // m.hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc() // diff --git a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go index c41ab37f3..de5a85629 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go @@ -48,7 +48,7 @@ func (e *expvarCollector) Collect(ch chan<- Metric) { continue } var v interface{} - labels := make([]string, len(desc.variableLabels)) + labels := make([]string, len(desc.variableLabels.names)) if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil { ch <- NewInvalidMetric(desc, err) continue diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go index 21271a5bb..dd2eac940 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go @@ -55,6 +55,18 @@ type Gauge interface { // GaugeOpts is an alias for Opts. See there for doc comments. type GaugeOpts Opts +// GaugeVecOpts bundles the options to create a GaugeVec metric. +// It is mandatory to set GaugeOpts, see there for mandatory fields. VariableLabels +// is optional and can safely be left to its default value. +type GaugeVecOpts struct { + GaugeOpts + + // VariableLabels are used to partition the metric vector by the given set + // of labels. Each label value will be constrained with the optional Constraint + // function, if provided. + VariableLabels ConstrainableLabels +} + // NewGauge creates a new Gauge based on the provided GaugeOpts. // // The returned implementation is optimized for a fast Set method. If you have a @@ -123,7 +135,7 @@ func (g *gauge) Sub(val float64) { func (g *gauge) Write(out *dto.Metric) error { val := math.Float64frombits(atomic.LoadUint64(&g.valBits)) - return populateMetric(GaugeValue, val, g.labelPairs, nil, out) + return populateMetric(GaugeValue, val, g.labelPairs, nil, out, nil) } // GaugeVec is a Collector that bundles a set of Gauges that all share the same @@ -138,16 +150,24 @@ type GaugeVec struct { // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and // partitioned by the given label names. func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { - desc := NewDesc( + return V2.NewGaugeVec(GaugeVecOpts{ + GaugeOpts: opts, + VariableLabels: UnconstrainedLabels(labelNames), + }) +} + +// NewGaugeVec creates a new GaugeVec based on the provided GaugeVecOpts. +func (v2) NewGaugeVec(opts GaugeVecOpts) *GaugeVec { + desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, - labelNames, + opts.VariableLabels, opts.ConstLabels, ) return &GaugeVec{ MetricVec: NewMetricVec(desc, func(lvs ...string) Metric { - if len(lvs) != len(desc.variableLabels) { - panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) + if len(lvs) != len(desc.variableLabels.names) { + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, lvs)) } result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)} result.init(result) // Init self-collection. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go index 3a2d55e84..2d8d9f64f 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_latest.go @@ -23,11 +23,10 @@ import ( "strings" "sync" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" - dto "github.com/prometheus/client_model/go" - "github.com/prometheus/client_golang/prometheus/internal" + + dto "github.com/prometheus/client_model/go" + "google.golang.org/protobuf/proto" ) const ( diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index 4c873a01c..b5c8bcb39 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -22,10 +22,10 @@ import ( "sync/atomic" "time" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" - dto "github.com/prometheus/client_model/go" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" ) // nativeHistogramBounds for the frac of observed values. Only relevant for @@ -392,7 +392,7 @@ type HistogramOpts struct { // zero, it is replaced by default buckets. The default buckets are // DefBuckets if no buckets for a native histogram (see below) are used, // otherwise the default is no buckets. (In other words, if you want to - // use both reguler buckets and buckets for a native histogram, you have + // use both regular buckets and buckets for a native histogram, you have // to define the regular buckets here explicitly.) Buckets []float64 @@ -402,7 +402,7 @@ type HistogramOpts struct { // Histogram by a Prometheus server with that feature enabled (requires // Prometheus v2.40+). Sparse buckets are exponential buckets covering // the whole float64 range (with the exception of the “zero” bucket, see - // SparseBucketsZeroThreshold below). From any one bucket to the next, + // NativeHistogramZeroThreshold below). From any one bucket to the next, // the width of the bucket grows by a constant // factor. NativeHistogramBucketFactor provides an upper bound for this // factor (exception see below). The smaller @@ -414,8 +414,8 @@ type HistogramOpts struct { // and 2, same as between 2 and 4, and 4 and 8, etc.). // // Details about the actually used factor: The factor is calculated as - // 2^(2^n), where n is an integer number between (and including) -8 and - // 4. n is chosen so that the resulting factor is the largest that is + // 2^(2^-n), where n is an integer number between (and including) -4 and + // 8. n is chosen so that the resulting factor is the largest that is // still smaller or equal to NativeHistogramBucketFactor. Note that the // smallest possible factor is therefore approx. 1.00271 (i.e. 2^(2^-8) // ). If NativeHistogramBucketFactor is greater than 1 but smaller than @@ -429,12 +429,12 @@ type HistogramOpts struct { // a major version bump. NativeHistogramBucketFactor float64 // All observations with an absolute value of less or equal - // NativeHistogramZeroThreshold are accumulated into a “zero” - // bucket. For best results, this should be close to a bucket - // boundary. This is usually the case if picking a power of two. If + // NativeHistogramZeroThreshold are accumulated into a “zero” bucket. + // For best results, this should be close to a bucket boundary. This is + // usually the case if picking a power of two. If // NativeHistogramZeroThreshold is left at zero, - // DefSparseBucketsZeroThreshold is used as the threshold. To configure - // a zero bucket with an actual threshold of zero (i.e. only + // DefNativeHistogramZeroThreshold is used as the threshold. To + // configure a zero bucket with an actual threshold of zero (i.e. only // observations of precisely zero will go into the zero bucket), set // NativeHistogramZeroThreshold to the NativeHistogramZeroThresholdZero // constant (or any negative float value). @@ -447,26 +447,49 @@ type HistogramOpts struct { // Histogram are sufficiently wide-spread. In particular, this could be // used as a DoS attack vector. Where the observed values depend on // external inputs, it is highly recommended to set a - // NativeHistogramMaxBucketNumber.) Once the set + // NativeHistogramMaxBucketNumber.) Once the set // NativeHistogramMaxBucketNumber is exceeded, the following strategy is - // enacted: First, if the last reset (or the creation) of the histogram - // is at least NativeHistogramMinResetDuration ago, then the whole - // histogram is reset to its initial state (including regular - // buckets). If less time has passed, or if - // NativeHistogramMinResetDuration is zero, no reset is - // performed. Instead, the zero threshold is increased sufficiently to - // reduce the number of buckets to or below - // NativeHistogramMaxBucketNumber, but not to more than - // NativeHistogramMaxZeroThreshold. Thus, if - // NativeHistogramMaxZeroThreshold is already at or below the current - // zero threshold, nothing happens at this step. After that, if the - // number of buckets still exceeds NativeHistogramMaxBucketNumber, the - // resolution of the histogram is reduced by doubling the width of the - // sparse buckets (up to a growth factor between one bucket to the next - // of 2^(2^4) = 65536, see above). + // enacted: + // - First, if the last reset (or the creation) of the histogram is at + // least NativeHistogramMinResetDuration ago, then the whole + // histogram is reset to its initial state (including regular + // buckets). + // - If less time has passed, or if NativeHistogramMinResetDuration is + // zero, no reset is performed. Instead, the zero threshold is + // increased sufficiently to reduce the number of buckets to or below + // NativeHistogramMaxBucketNumber, but not to more than + // NativeHistogramMaxZeroThreshold. Thus, if + // NativeHistogramMaxZeroThreshold is already at or below the current + // zero threshold, nothing happens at this step. + // - After that, if the number of buckets still exceeds + // NativeHistogramMaxBucketNumber, the resolution of the histogram is + // reduced by doubling the width of the sparse buckets (up to a + // growth factor between one bucket to the next of 2^(2^4) = 65536, + // see above). + // - Any increased zero threshold or reduced resolution is reset back + // to their original values once NativeHistogramMinResetDuration has + // passed (since the last reset or the creation of the histogram). NativeHistogramMaxBucketNumber uint32 NativeHistogramMinResetDuration time.Duration NativeHistogramMaxZeroThreshold float64 + + // now is for testing purposes, by default it's time.Now. + now func() time.Time + + // afterFunc is for testing purposes, by default it's time.AfterFunc. + afterFunc func(time.Duration, func()) *time.Timer +} + +// HistogramVecOpts bundles the options to create a HistogramVec metric. +// It is mandatory to set HistogramOpts, see there for mandatory fields. VariableLabels +// is optional and can safely be left to its default value. +type HistogramVecOpts struct { + HistogramOpts + + // VariableLabels are used to partition the metric vector by the given set + // of labels. Each label value will be constrained with the optional Constraint + // function, if provided. + VariableLabels ConstrainableLabels } // NewHistogram creates a new Histogram based on the provided HistogramOpts. It @@ -488,11 +511,11 @@ func NewHistogram(opts HistogramOpts) Histogram { } func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram { - if len(desc.variableLabels) != len(labelValues) { - panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) + if len(desc.variableLabels.names) != len(labelValues) { + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, labelValues)) } - for _, n := range desc.variableLabels { + for _, n := range desc.variableLabels.names { if n == bucketLabel { panic(errBucketLabelNotAllowed) } @@ -503,6 +526,12 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } } + if opts.now == nil { + opts.now = time.Now + } + if opts.afterFunc == nil { + opts.afterFunc = time.AfterFunc + } h := &histogram{ desc: desc, upperBounds: opts.Buckets, @@ -510,8 +539,9 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr nativeHistogramMaxBuckets: opts.NativeHistogramMaxBucketNumber, nativeHistogramMaxZeroThreshold: opts.NativeHistogramMaxZeroThreshold, nativeHistogramMinResetDuration: opts.NativeHistogramMinResetDuration, - lastResetTime: time.Now(), - now: time.Now, + lastResetTime: opts.now(), + now: opts.now, + afterFunc: opts.afterFunc, } if len(h.upperBounds) == 0 && opts.NativeHistogramBucketFactor <= 1 { h.upperBounds = DefBuckets @@ -544,16 +574,12 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } // Finally we know the final length of h.upperBounds and can make buckets // for both counts as well as exemplars: - h.counts[0] = &histogramCounts{ - buckets: make([]uint64, len(h.upperBounds)), - nativeHistogramZeroThresholdBits: math.Float64bits(h.nativeHistogramZeroThreshold), - nativeHistogramSchema: h.nativeHistogramSchema, - } - h.counts[1] = &histogramCounts{ - buckets: make([]uint64, len(h.upperBounds)), - nativeHistogramZeroThresholdBits: math.Float64bits(h.nativeHistogramZeroThreshold), - nativeHistogramSchema: h.nativeHistogramSchema, - } + h.counts[0] = &histogramCounts{buckets: make([]uint64, len(h.upperBounds))} + atomic.StoreUint64(&h.counts[0].nativeHistogramZeroThresholdBits, math.Float64bits(h.nativeHistogramZeroThreshold)) + atomic.StoreInt32(&h.counts[0].nativeHistogramSchema, h.nativeHistogramSchema) + h.counts[1] = &histogramCounts{buckets: make([]uint64, len(h.upperBounds))} + atomic.StoreUint64(&h.counts[1].nativeHistogramZeroThresholdBits, math.Float64bits(h.nativeHistogramZeroThreshold)) + atomic.StoreInt32(&h.counts[1].nativeHistogramSchema, h.nativeHistogramSchema) h.exemplars = make([]atomic.Value, len(h.upperBounds)+1) h.init(h) // Init self-collection. @@ -632,8 +658,8 @@ func (hc *histogramCounts) observe(v float64, bucket int, doSparse bool) { if frac == 0.5 { key-- } - div := 1 << -schema - key = (key + div - 1) / div + offset := (1 << -schema) - 1 + key = (key + offset) >> -schema } if isInf { key++ @@ -694,9 +720,18 @@ type histogram struct { nativeHistogramMaxZeroThreshold float64 nativeHistogramMaxBuckets uint32 nativeHistogramMinResetDuration time.Duration - lastResetTime time.Time // Protected by mtx. - - now func() time.Time // To mock out time.Now() for testing. + // lastResetTime is protected by mtx. It is also used as created timestamp. + lastResetTime time.Time + // resetScheduled is protected by mtx. It is true if a reset is + // scheduled for a later time (when nativeHistogramMinResetDuration has + // passed). + resetScheduled bool + + // now is for testing purposes, by default it's time.Now. + now func() time.Time + + // afterFunc is for testing purposes, by default it's time.AfterFunc. + afterFunc func(time.Duration, func()) *time.Timer } func (h *histogram) Desc() *Desc { @@ -735,9 +770,10 @@ func (h *histogram) Write(out *dto.Metric) error { waitForCooldown(count, coldCounts) his := &dto.Histogram{ - Bucket: make([]*dto.Bucket, len(h.upperBounds)), - SampleCount: proto.Uint64(count), - SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + Bucket: make([]*dto.Bucket, len(h.upperBounds)), + SampleCount: proto.Uint64(count), + SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + CreatedTimestamp: timestamppb.New(h.lastResetTime), } out.Histogram = his out.Label = h.labelPairs @@ -775,6 +811,16 @@ func (h *histogram) Write(out *dto.Metric) error { his.ZeroCount = proto.Uint64(zeroBucket) his.NegativeSpan, his.NegativeDelta = makeBuckets(&coldCounts.nativeHistogramBucketsNegative) his.PositiveSpan, his.PositiveDelta = makeBuckets(&coldCounts.nativeHistogramBucketsPositive) + + // Add a no-op span to a histogram without observations and with + // a zero threshold of zero. Otherwise, a native histogram would + // look like a classic histogram to scrapers. + if *his.ZeroThreshold == 0 && *his.ZeroCount == 0 && len(his.PositiveSpan) == 0 && len(his.NegativeSpan) == 0 { + his.PositiveSpan = []*dto.BucketSpan{{ + Offset: proto.Int32(0), + Length: proto.Uint32(0), + }} + } } addAndResetCounts(hotCounts, coldCounts) return nil @@ -810,7 +856,7 @@ func (h *histogram) observe(v float64, bucket int) { } } -// limitSparsebuckets applies a strategy to limit the number of populated sparse +// limitBuckets applies a strategy to limit the number of populated sparse // buckets. It's generally best effort, and there are situations where the // number can go higher (if even the lowest resolution isn't enough to reduce // the number sufficiently, or if the provided counts aren't fully updated yet @@ -841,26 +887,39 @@ func (h *histogram) limitBuckets(counts *histogramCounts, value float64, bucket if h.maybeReset(hotCounts, coldCounts, coldIdx, value, bucket) { return } + // One of the other strategies will happen. To undo what they will do as + // soon as enough time has passed to satisfy + // h.nativeHistogramMinResetDuration, schedule a reset at the right time + // if we haven't done so already. + if h.nativeHistogramMinResetDuration > 0 && !h.resetScheduled { + h.resetScheduled = true + h.afterFunc(h.nativeHistogramMinResetDuration-h.now().Sub(h.lastResetTime), h.reset) + } + if h.maybeWidenZeroBucket(hotCounts, coldCounts) { return } h.doubleBucketWidth(hotCounts, coldCounts) } -// maybeReset resests the whole histogram if at least h.nativeHistogramMinResetDuration -// has been passed. It returns true if the histogram has been reset. The caller -// must have locked h.mtx. -func (h *histogram) maybeReset(hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int) bool { +// maybeReset resets the whole histogram if at least +// h.nativeHistogramMinResetDuration has been passed. It returns true if the +// histogram has been reset. The caller must have locked h.mtx. +func (h *histogram) maybeReset( + hot, cold *histogramCounts, coldIdx uint64, value float64, bucket int, +) bool { // We are using the possibly mocked h.now() rather than // time.Since(h.lastResetTime) to enable testing. - if h.nativeHistogramMinResetDuration == 0 || h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration { + if h.nativeHistogramMinResetDuration == 0 || // No reset configured. + h.resetScheduled || // Do not interefere if a reset is already scheduled. + h.now().Sub(h.lastResetTime) < h.nativeHistogramMinResetDuration { return false } // Completely reset coldCounts. h.resetCounts(cold) // Repeat the latest observation to not lose it completely. cold.observe(value, bucket, true) - // Make coldCounts the new hot counts while ressetting countAndHotIdx. + // Make coldCounts the new hot counts while resetting countAndHotIdx. n := atomic.SwapUint64(&h.countAndHotIdx, (coldIdx<<63)+1) count := n & ((1 << 63) - 1) waitForCooldown(count, hot) @@ -870,6 +929,29 @@ func (h *histogram) maybeReset(hot, cold *histogramCounts, coldIdx uint64, value return true } +// reset resets the whole histogram. It locks h.mtx itself, i.e. it has to be +// called without having locked h.mtx. +func (h *histogram) reset() { + h.mtx.Lock() + defer h.mtx.Unlock() + + n := atomic.LoadUint64(&h.countAndHotIdx) + hotIdx := n >> 63 + coldIdx := (^n) >> 63 + hot := h.counts[hotIdx] + cold := h.counts[coldIdx] + // Completely reset coldCounts. + h.resetCounts(cold) + // Make coldCounts the new hot counts while resetting countAndHotIdx. + n = atomic.SwapUint64(&h.countAndHotIdx, coldIdx<<63) + count := n & ((1 << 63) - 1) + waitForCooldown(count, hot) + // Finally, reset the formerly hot counts, too. + h.resetCounts(hot) + h.lastResetTime = h.now() + h.resetScheduled = false +} + // maybeWidenZeroBucket widens the zero bucket until it includes the existing // buckets closest to the zero bucket (which could be two, if an equidistant // negative and a positive bucket exists, but usually it's only one bucket to be @@ -1034,15 +1116,23 @@ type HistogramVec struct { // NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and // partitioned by the given label names. func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec { - desc := NewDesc( + return V2.NewHistogramVec(HistogramVecOpts{ + HistogramOpts: opts, + VariableLabels: UnconstrainedLabels(labelNames), + }) +} + +// NewHistogramVec creates a new HistogramVec based on the provided HistogramVecOpts. +func (v2) NewHistogramVec(opts HistogramVecOpts) *HistogramVec { + desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, - labelNames, + opts.VariableLabels, opts.ConstLabels, ) return &HistogramVec{ MetricVec: NewMetricVec(desc, func(lvs ...string) Metric { - return newHistogram(desc, opts, lvs...) + return newHistogram(desc, opts.HistogramOpts, lvs...) }), } } @@ -1161,6 +1251,7 @@ type constHistogram struct { sum float64 buckets map[float64]uint64 labelPairs []*dto.LabelPair + createdTs *timestamppb.Timestamp } func (h *constHistogram) Desc() *Desc { @@ -1168,7 +1259,9 @@ func (h *constHistogram) Desc() *Desc { } func (h *constHistogram) Write(out *dto.Metric) error { - his := &dto.Histogram{} + his := &dto.Histogram{ + CreatedTimestamp: h.createdTs, + } buckets := make([]*dto.Bucket, 0, len(h.buckets)) @@ -1215,7 +1308,7 @@ func NewConstHistogram( if desc.err != nil { return nil, desc.err } - if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { + if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil { return nil, err } return &constHistogram{ @@ -1309,7 +1402,7 @@ func makeBuckets(buckets *sync.Map) ([]*dto.BucketSpan, []int64) { // Multiple spans with only small gaps in between are probably // encoded more efficiently as one larger span with a few empty // buckets. Needs some research to find the sweet spot. For now, - // we assume that gaps of one ore two buckets should not create + // we assume that gaps of one or two buckets should not create // a new span. iDelta := int32(i - nextI) if n == 0 || iDelta > 2 { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go b/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go index fd0750f2c..a595a2036 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/internal/difflib.go @@ -14,7 +14,7 @@ // It provides tools to compare sequences of strings and generate textual diffs. // // Maintaining `GetUnifiedDiffString` here because original repository -// (https://github.com/pmezard/go-difflib) is no loger maintained. +// (https://github.com/pmezard/go-difflib) is no longer maintained. package internal import ( diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go index c1b8fad36..c21911f29 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/labels.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go @@ -32,6 +32,104 @@ import ( // create a Desc. type Labels map[string]string +// LabelConstraint normalizes label values. +type LabelConstraint func(string) string + +// ConstrainedLabels represents a label name and its constrain function +// to normalize label values. This type is commonly used when constructing +// metric vector Collectors. +type ConstrainedLabel struct { + Name string + Constraint LabelConstraint +} + +// ConstrainableLabels is an interface that allows creating of labels that can +// be optionally constrained. +// +// prometheus.V2().NewCounterVec(CounterVecOpts{ +// CounterOpts: {...}, // Usual CounterOpts fields +// VariableLabels: []ConstrainedLabels{ +// {Name: "A"}, +// {Name: "B", Constraint: func(v string) string { ... }}, +// }, +// }) +type ConstrainableLabels interface { + compile() *compiledLabels + labelNames() []string +} + +// ConstrainedLabels represents a collection of label name -> constrain function +// to normalize label values. This type is commonly used when constructing +// metric vector Collectors. +type ConstrainedLabels []ConstrainedLabel + +func (cls ConstrainedLabels) compile() *compiledLabels { + compiled := &compiledLabels{ + names: make([]string, len(cls)), + labelConstraints: map[string]LabelConstraint{}, + } + + for i, label := range cls { + compiled.names[i] = label.Name + if label.Constraint != nil { + compiled.labelConstraints[label.Name] = label.Constraint + } + } + + return compiled +} + +func (cls ConstrainedLabels) labelNames() []string { + names := make([]string, len(cls)) + for i, label := range cls { + names[i] = label.Name + } + return names +} + +// UnconstrainedLabels represents collection of label without any constraint on +// their value. Thus, it is simply a collection of label names. +// +// UnconstrainedLabels([]string{ "A", "B" }) +// +// is equivalent to +// +// ConstrainedLabels { +// { Name: "A" }, +// { Name: "B" }, +// } +type UnconstrainedLabels []string + +func (uls UnconstrainedLabels) compile() *compiledLabels { + return &compiledLabels{ + names: uls, + } +} + +func (uls UnconstrainedLabels) labelNames() []string { + return uls +} + +type compiledLabels struct { + names []string + labelConstraints map[string]LabelConstraint +} + +func (cls *compiledLabels) compile() *compiledLabels { + return cls +} + +func (cls *compiledLabels) labelNames() []string { + return cls.names +} + +func (cls *compiledLabels) constrain(labelName, value string) string { + if fn, ok := cls.labelConstraints[labelName]; ok && fn != nil { + return fn(value) + } + return value +} + // reservedLabelPrefix is a prefix which is not legal in user-supplied // label names. const reservedLabelPrefix = "__" @@ -67,6 +165,8 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { func validateLabelValues(vals []string, expectedNumberOfValues int) error { if len(vals) != expectedNumberOfValues { + // The call below makes vals escape, copy them to avoid that. + vals := append([]string(nil), vals...) return fmt.Errorf( "%w: expected %d label values but got %d in %#v", errInconsistentCardinality, expectedNumberOfValues, diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric.go b/vendor/github.com/prometheus/client_golang/prometheus/metric.go index b5119c504..f018e5723 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/metric.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/metric.go @@ -20,11 +20,9 @@ import ( "strings" "time" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" - "github.com/prometheus/common/model" - dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/model" + "google.golang.org/protobuf/proto" ) var separatorByteSlice = []byte{model.SeparatorByte} // For convenient use with xxhash. @@ -94,6 +92,9 @@ type Opts struct { // machine_role metric). See also // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels ConstLabels Labels + + // now is for testing purposes, by default it's time.Now. + now func() time.Time } // BuildFQName joins the given three name components by "_". Empty name diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go index c0152cdb6..8c1136cee 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_other.go @@ -11,8 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !windows && !js -// +build !windows,!js +//go:build !windows && !js && !wasip1 +// +build !windows,!js,!wasip1 package prometheus diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_wasip1.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_wasip1.go new file mode 100644 index 000000000..d8d9a6d7a --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_wasip1.go @@ -0,0 +1,26 @@ +// Copyright 2023 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. + +//go:build wasip1 +// +build wasip1 + +package prometheus + +func canCollectProcess() bool { + return false +} + +func (*processCollector) processCollect(chan<- Metric) { + // noop on this platform + return +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go index a4cc9810b..09b8d2fbe 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -37,6 +37,7 @@ import ( "fmt" "io" "net/http" + "strconv" "strings" "sync" "time" @@ -47,9 +48,10 @@ import ( ) const ( - contentTypeHeader = "Content-Type" - contentEncodingHeader = "Content-Encoding" - acceptEncodingHeader = "Accept-Encoding" + contentTypeHeader = "Content-Type" + contentEncodingHeader = "Content-Encoding" + acceptEncodingHeader = "Accept-Encoding" + processStartTimeHeader = "Process-Start-Time-Unix" ) var gzipPool = sync.Pool{ @@ -121,6 +123,9 @@ func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerO } h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { + if !opts.ProcessStartTime.IsZero() { + rsp.Header().Set(processStartTimeHeader, strconv.FormatInt(opts.ProcessStartTime.Unix(), 10)) + } if inFlightSem != nil { select { case inFlightSem <- struct{}{}: // All good, carry on. @@ -366,6 +371,14 @@ type HandlerOpts struct { // (which changes the identity of the resulting series on the Prometheus // server). EnableOpenMetrics bool + // ProcessStartTime allows setting process start timevalue that will be exposed + // with "Process-Start-Time-Unix" response header along with the metrics + // payload. This allow callers to have efficient transformations to cumulative + // counters (e.g. OpenTelemetry) or generally _created timestamp estimation per + // scrape target. + // NOTE: This feature is experimental and not covered by OpenMetrics or Prometheus + // exposition format. + ProcessStartTime time.Time } // gzipAccepted returns whether the client will accept gzip-encoded content. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go index 210867816..d3482c40c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go @@ -68,16 +68,17 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou o.apply(rtOpts) } - code, method := checkLabels(counter) + // Curry the counter with dynamic labels before checking the remaining labels. + code, method := checkLabels(counter.MustCurryWith(rtOpts.emptyDynamicLabels())) return func(r *http.Request) (*http.Response, error) { resp, err := next.RoundTrip(r) if err == nil { - addWithExemplar( - counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)), - 1, - rtOpts.getExemplarFn(r.Context()), - ) + l := labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...) + for label, resolve := range rtOpts.extraLabelsFromCtx { + l[label] = resolve(resp.Request.Context()) + } + addWithExemplar(counter.With(l), 1, rtOpts.getExemplarFn(r.Context())) } return resp, err } @@ -110,17 +111,18 @@ func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundT o.apply(rtOpts) } - code, method := checkLabels(obs) + // Curry the observer with dynamic labels before checking the remaining labels. + code, method := checkLabels(obs.MustCurryWith(rtOpts.emptyDynamicLabels())) return func(r *http.Request) (*http.Response, error) { start := time.Now() resp, err := next.RoundTrip(r) if err == nil { - observeWithExemplar( - obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)), - time.Since(start).Seconds(), - rtOpts.getExemplarFn(r.Context()), - ) + l := labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...) + for label, resolve := range rtOpts.extraLabelsFromCtx { + l[label] = resolve(resp.Request.Context()) + } + observeWithExemplar(obs.With(l), time.Since(start).Seconds(), rtOpts.getExemplarFn(r.Context())) } return resp, err } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go index cca67a78a..356edb786 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go @@ -87,7 +87,8 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op o.apply(hOpts) } - code, method := checkLabels(obs) + // Curry the observer with dynamic labels before checking the remaining labels. + code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels())) if code { return func(w http.ResponseWriter, r *http.Request) { @@ -95,23 +96,22 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op d := newDelegator(w, nil) next.ServeHTTP(d, r) - observeWithExemplar( - obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), - time.Since(now).Seconds(), - hOpts.getExemplarFn(r.Context()), - ) + l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context())) } } return func(w http.ResponseWriter, r *http.Request) { now := time.Now() next.ServeHTTP(w, r) - - observeWithExemplar( - obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)), - time.Since(now).Seconds(), - hOpts.getExemplarFn(r.Context()), - ) + l := labels(code, method, r.Method, 0, hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context())) } } @@ -138,28 +138,30 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, o.apply(hOpts) } - code, method := checkLabels(counter) + // Curry the counter with dynamic labels before checking the remaining labels. + code, method := checkLabels(counter.MustCurryWith(hOpts.emptyDynamicLabels())) if code { return func(w http.ResponseWriter, r *http.Request) { d := newDelegator(w, nil) next.ServeHTTP(d, r) - addWithExemplar( - counter.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), - 1, - hOpts.getExemplarFn(r.Context()), - ) + l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context())) } } return func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) - addWithExemplar( - counter.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)), - 1, - hOpts.getExemplarFn(r.Context()), - ) + + l := labels(code, method, r.Method, 0, hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + addWithExemplar(counter.With(l), 1, hOpts.getExemplarFn(r.Context())) } } @@ -191,16 +193,17 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha o.apply(hOpts) } - code, method := checkLabels(obs) + // Curry the observer with dynamic labels before checking the remaining labels. + code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels())) return func(w http.ResponseWriter, r *http.Request) { now := time.Now() d := newDelegator(w, func(status int) { - observeWithExemplar( - obs.With(labels(code, method, r.Method, status, hOpts.extraMethods...)), - time.Since(now).Seconds(), - hOpts.getExemplarFn(r.Context()), - ) + l := labels(code, method, r.Method, status, hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + observeWithExemplar(obs.With(l), time.Since(now).Seconds(), hOpts.getExemplarFn(r.Context())) }) next.ServeHTTP(d, r) } @@ -231,28 +234,32 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, o.apply(hOpts) } - code, method := checkLabels(obs) + // Curry the observer with dynamic labels before checking the remaining labels. + code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels())) + if code { return func(w http.ResponseWriter, r *http.Request) { d := newDelegator(w, nil) next.ServeHTTP(d, r) size := computeApproximateRequestSize(r) - observeWithExemplar( - obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), - float64(size), - hOpts.getExemplarFn(r.Context()), - ) + + l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context())) } } return func(w http.ResponseWriter, r *http.Request) { next.ServeHTTP(w, r) size := computeApproximateRequestSize(r) - observeWithExemplar( - obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)), - float64(size), - hOpts.getExemplarFn(r.Context()), - ) + + l := labels(code, method, r.Method, 0, hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + observeWithExemplar(obs.With(l), float64(size), hOpts.getExemplarFn(r.Context())) } } @@ -281,16 +288,18 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler o.apply(hOpts) } - code, method := checkLabels(obs) + // Curry the observer with dynamic labels before checking the remaining labels. + code, method := checkLabels(obs.MustCurryWith(hOpts.emptyDynamicLabels())) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { d := newDelegator(w, nil) next.ServeHTTP(d, r) - observeWithExemplar( - obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)), - float64(d.Written()), - hOpts.getExemplarFn(r.Context()), - ) + + l := labels(code, method, r.Method, d.Status(), hOpts.extraMethods...) + for label, resolve := range hOpts.extraLabelsFromCtx { + l[label] = resolve(r.Context()) + } + observeWithExemplar(obs.With(l), float64(d.Written()), hOpts.getExemplarFn(r.Context())) }) } @@ -380,15 +389,12 @@ func isLabelCurried(c prometheus.Collector, label string) bool { return true } -// emptyLabels is a one-time allocation for non-partitioned metrics to avoid -// unnecessary allocations on each request. -var emptyLabels = prometheus.Labels{} - func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels { + labels := prometheus.Labels{} + if !(code || method) { - return emptyLabels + return labels } - labels := prometheus.Labels{} if code { labels["code"] = sanitizeCode(status) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go index c590d912c..5d4383aa1 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go @@ -24,14 +24,32 @@ type Option interface { apply(*options) } +// LabelValueFromCtx are used to compute the label value from request context. +// Context can be filled with values from request through middleware. +type LabelValueFromCtx func(ctx context.Context) string + // options store options for both a handler or round tripper. type options struct { - extraMethods []string - getExemplarFn func(requestCtx context.Context) prometheus.Labels + extraMethods []string + getExemplarFn func(requestCtx context.Context) prometheus.Labels + extraLabelsFromCtx map[string]LabelValueFromCtx } func defaultOptions() *options { - return &options{getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil }} + return &options{ + getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil }, + extraLabelsFromCtx: map[string]LabelValueFromCtx{}, + } +} + +func (o *options) emptyDynamicLabels() prometheus.Labels { + labels := prometheus.Labels{} + + for label := range o.extraLabelsFromCtx { + labels[label] = "" + } + + return labels } type optionApplyFunc func(*options) @@ -48,11 +66,19 @@ func WithExtraMethods(methods ...string) Option { }) } -// WithExemplarFromContext adds allows to put a hook to all counter and histogram metrics. -// If the hook function returns non-nil labels, exemplars will be added for that request, otherwise metric -// will get instrumented without exemplar. +// WithExemplarFromContext allows to inject function that will get exemplar from context that will be put to counter and histogram metrics. +// If the function returns nil labels or the metric does not support exemplars, no exemplar will be added (noop), but +// metric will continue to observe/increment. func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option { return optionApplyFunc(func(o *options) { o.getExemplarFn = getExemplarFn }) } + +// WithLabelFromCtx registers a label for dynamic resolution with access to context. +// See the example for ExampleInstrumentHandlerWithLabelResolver for example usage +func WithLabelFromCtx(name string, valueFn LabelValueFromCtx) Option { + return optionApplyFunc(func(o *options) { + o.extraLabelsFromCtx[name] = valueFn + }) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index 09e34d307..5e2ced25a 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -21,18 +21,17 @@ import ( "path/filepath" "runtime" "sort" + "strconv" "strings" "sync" "unicode/utf8" - "github.com/cespare/xxhash/v2" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" - "github.com/prometheus/common/expfmt" + "github.com/prometheus/client_golang/prometheus/internal" + "github.com/cespare/xxhash/v2" dto "github.com/prometheus/client_model/go" - - "github.com/prometheus/client_golang/prometheus/internal" + "github.com/prometheus/common/expfmt" + "google.golang.org/protobuf/proto" ) const ( @@ -549,7 +548,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { goroutineBudget-- runtime.Gosched() } - // Once both checkedMetricChan and uncheckdMetricChan are closed + // Once both checkedMetricChan and uncheckedMetricChan are closed // and drained, the contraption above will nil out cmc and umc, // and then we can leave the collect loop here. if cmc == nil && umc == nil { @@ -933,6 +932,10 @@ func checkMetricConsistency( h.WriteString(lp.GetValue()) h.Write(separatorByteSlice) } + if dtoMetric.TimestampMs != nil { + h.WriteString(strconv.FormatInt(*(dtoMetric.TimestampMs), 10)) + h.Write(separatorByteSlice) + } hSum := h.Sum64() if _, exists := metricHashes[hSum]; exists { return fmt.Errorf( @@ -960,7 +963,7 @@ func checkDescConsistency( // Is the desc consistent with the content of the metric? lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label)) copy(lpsFromDesc, desc.constLabelPairs) - for _, l := range desc.variableLabels { + for _, l := range desc.variableLabels.names { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ Name: proto.String(l), }) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index 7bc448a89..146270444 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -22,11 +22,11 @@ import ( "sync/atomic" "time" - "github.com/beorn7/perks/quantile" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" - dto "github.com/prometheus/client_model/go" + + "github.com/beorn7/perks/quantile" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" ) // quantileLabel is used for the label that defines the quantile in a @@ -146,6 +146,21 @@ type SummaryOpts struct { // is the internal buffer size of the underlying package // "github.com/bmizerany/perks/quantile"). BufCap uint32 + + // now is for testing purposes, by default it's time.Now. + now func() time.Time +} + +// SummaryVecOpts bundles the options to create a SummaryVec metric. +// It is mandatory to set SummaryOpts, see there for mandatory fields. VariableLabels +// is optional and can safely be left to its default value. +type SummaryVecOpts struct { + SummaryOpts + + // VariableLabels are used to partition the metric vector by the given set + // of labels. Each label value will be constrained with the optional Constraint + // function, if provided. + VariableLabels ConstrainableLabels } // Problem with the sliding-window decay algorithm... The Merge method of @@ -177,11 +192,11 @@ func NewSummary(opts SummaryOpts) Summary { } func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { - if len(desc.variableLabels) != len(labelValues) { - panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) + if len(desc.variableLabels.names) != len(labelValues) { + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.names, labelValues)) } - for _, n := range desc.variableLabels { + for _, n := range desc.variableLabels.names { if n == quantileLabel { panic(errQuantileLabelNotAllowed) } @@ -211,6 +226,9 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { opts.BufCap = DefBufCap } + if opts.now == nil { + opts.now = time.Now + } if len(opts.Objectives) == 0 { // Use the lock-free implementation of a Summary without objectives. s := &noObjectivesSummary{ @@ -219,6 +237,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { counts: [2]*summaryCounts{{}, {}}, } s.init(s) // Init self-collection. + s.createdTs = timestamppb.New(opts.now()) return s } @@ -234,7 +253,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { coldBuf: make([]float64, 0, opts.BufCap), streamDuration: opts.MaxAge / time.Duration(opts.AgeBuckets), } - s.headStreamExpTime = time.Now().Add(s.streamDuration) + s.headStreamExpTime = opts.now().Add(s.streamDuration) s.hotBufExpTime = s.headStreamExpTime for i := uint32(0); i < opts.AgeBuckets; i++ { @@ -248,6 +267,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { sort.Float64s(s.sortedObjectives) s.init(s) // Init self-collection. + s.createdTs = timestamppb.New(opts.now()) return s } @@ -275,6 +295,8 @@ type summary struct { headStream *quantile.Stream headStreamIdx int headStreamExpTime, hotBufExpTime time.Time + + createdTs *timestamppb.Timestamp } func (s *summary) Desc() *Desc { @@ -296,7 +318,9 @@ func (s *summary) Observe(v float64) { } func (s *summary) Write(out *dto.Metric) error { - sum := &dto.Summary{} + sum := &dto.Summary{ + CreatedTimestamp: s.createdTs, + } qs := make([]*dto.Quantile, 0, len(s.objectives)) s.bufMtx.Lock() @@ -429,6 +453,8 @@ type noObjectivesSummary struct { counts [2]*summaryCounts labelPairs []*dto.LabelPair + + createdTs *timestamppb.Timestamp } func (s *noObjectivesSummary) Desc() *Desc { @@ -479,8 +505,9 @@ func (s *noObjectivesSummary) Write(out *dto.Metric) error { } sum := &dto.Summary{ - SampleCount: proto.Uint64(count), - SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + SampleCount: proto.Uint64(count), + SampleSum: proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))), + CreatedTimestamp: s.createdTs, } out.Summary = sum @@ -530,20 +557,28 @@ type SummaryVec struct { // it is handled by the Prometheus server internally, “quantile” is an illegal // label name. NewSummaryVec will panic if this label name is used. func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec { - for _, ln := range labelNames { + return V2.NewSummaryVec(SummaryVecOpts{ + SummaryOpts: opts, + VariableLabels: UnconstrainedLabels(labelNames), + }) +} + +// NewSummaryVec creates a new SummaryVec based on the provided SummaryVecOpts. +func (v2) NewSummaryVec(opts SummaryVecOpts) *SummaryVec { + for _, ln := range opts.VariableLabels.labelNames() { if ln == quantileLabel { panic(errQuantileLabelNotAllowed) } } - desc := NewDesc( + desc := V2.NewDesc( BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), opts.Help, - labelNames, + opts.VariableLabels, opts.ConstLabels, ) return &SummaryVec{ MetricVec: NewMetricVec(desc, func(lvs ...string) Metric { - return newSummary(desc, opts, lvs...) + return newSummary(desc, opts.SummaryOpts, lvs...) }), } } @@ -662,6 +697,7 @@ type constSummary struct { sum float64 quantiles map[float64]float64 labelPairs []*dto.LabelPair + createdTs *timestamppb.Timestamp } func (s *constSummary) Desc() *Desc { @@ -669,7 +705,9 @@ func (s *constSummary) Desc() *Desc { } func (s *constSummary) Write(out *dto.Metric) error { - sum := &dto.Summary{} + sum := &dto.Summary{ + CreatedTimestamp: s.createdTs, + } qs := make([]*dto.Quantile, 0, len(s.quantiles)) sum.SampleCount = proto.Uint64(s.count) @@ -718,7 +756,7 @@ func NewConstSummary( if desc.err != nil { return nil, desc.err } - if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { + if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil { return nil, err } return &constSummary{ diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/problem.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/problem.go new file mode 100644 index 000000000..9ba42826a --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/problem.go @@ -0,0 +1,33 @@ +// Copyright 2020 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 promlint + +import dto "github.com/prometheus/client_model/go" + +// A Problem is an issue detected by a linter. +type Problem struct { + // The name of the metric indicated by this Problem. + Metric string + + // A description of the issue for this Problem. + Text string +} + +// newProblem is helper function to create a Problem. +func newProblem(mf *dto.MetricFamily, text string) Problem { + return Problem{ + Metric: mf.GetName(), + Text: text, + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go index a20f159b7..ea46f38ec 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/promlint.go @@ -16,15 +16,11 @@ package promlint import ( "errors" - "fmt" "io" - "regexp" "sort" - "strings" - - "github.com/prometheus/common/expfmt" dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" ) // A Linter is a Prometheus metrics linter. It identifies issues with metric @@ -37,23 +33,8 @@ type Linter struct { // of them. r io.Reader mfs []*dto.MetricFamily -} -// A Problem is an issue detected by a Linter. -type Problem struct { - // The name of the metric indicated by this Problem. - Metric string - - // A description of the issue for this Problem. - Text string -} - -// newProblem is helper function to create a Problem. -func newProblem(mf *dto.MetricFamily, text string) Problem { - return Problem{ - Metric: mf.GetName(), - Text: text, - } + customValidations []Validation } // New creates a new Linter that reads an input stream of Prometheus metrics in @@ -72,6 +53,14 @@ func NewWithMetricFamilies(mfs []*dto.MetricFamily) *Linter { } } +// AddCustomValidations adds custom validations to the linter. +func (l *Linter) AddCustomValidations(vs ...Validation) { + if l.customValidations == nil { + l.customValidations = make([]Validation, 0, len(vs)) + } + l.customValidations = append(l.customValidations, vs...) +} + // Lint performs a linting pass, returning a slice of Problems indicating any // issues found in the metrics stream. The slice is sorted by metric name // and issue description. @@ -79,7 +68,7 @@ func (l *Linter) Lint() ([]Problem, error) { var problems []Problem if l.r != nil { - d := expfmt.NewDecoder(l.r, expfmt.FmtText) + d := expfmt.NewDecoder(l.r, expfmt.NewFormat(expfmt.TypeTextPlain)) mf := &dto.MetricFamily{} for { @@ -91,11 +80,11 @@ func (l *Linter) Lint() ([]Problem, error) { return nil, err } - problems = append(problems, lint(mf)...) + problems = append(problems, l.lint(mf)...) } } for _, mf := range l.mfs { - problems = append(problems, lint(mf)...) + problems = append(problems, l.lint(mf)...) } // Ensure deterministic output. @@ -110,278 +99,25 @@ func (l *Linter) Lint() ([]Problem, error) { } // lint is the entry point for linting a single metric. -func lint(mf *dto.MetricFamily) []Problem { - fns := []func(mf *dto.MetricFamily) []Problem{ - lintHelp, - lintMetricUnits, - lintCounter, - lintHistogramSummaryReserved, - lintMetricTypeInName, - lintReservedChars, - lintCamelCase, - lintUnitAbbreviations, - } - - var problems []Problem - for _, fn := range fns { - problems = append(problems, fn(mf)...) - } - - // TODO(mdlayher): lint rules for specific metrics types. - return problems -} - -// lintHelp detects issues related to the help text for a metric. -func lintHelp(mf *dto.MetricFamily) []Problem { - var problems []Problem - - // Expect all metrics to have help text available. - if mf.Help == nil { - problems = append(problems, newProblem(mf, "no help text")) - } - - return problems -} - -// lintMetricUnits detects issues with metric unit names. -func lintMetricUnits(mf *dto.MetricFamily) []Problem { +func (l *Linter) lint(mf *dto.MetricFamily) []Problem { var problems []Problem - unit, base, ok := metricUnits(*mf.Name) - if !ok { - // No known units detected. - return nil - } - - // Unit is already a base unit. - if unit == base { - return nil - } - - problems = append(problems, newProblem(mf, fmt.Sprintf("use base unit %q instead of %q", base, unit))) - - return problems -} - -// lintCounter detects issues specific to counters, as well as patterns that should -// only be used with counters. -func lintCounter(mf *dto.MetricFamily) []Problem { - var problems []Problem - - isCounter := mf.GetType() == dto.MetricType_COUNTER - isUntyped := mf.GetType() == dto.MetricType_UNTYPED - hasTotalSuffix := strings.HasSuffix(mf.GetName(), "_total") - - switch { - case isCounter && !hasTotalSuffix: - problems = append(problems, newProblem(mf, `counter metrics should have "_total" suffix`)) - case !isUntyped && !isCounter && hasTotalSuffix: - problems = append(problems, newProblem(mf, `non-counter metrics should not have "_total" suffix`)) - } - - return problems -} - -// lintHistogramSummaryReserved detects when other types of metrics use names or labels -// reserved for use by histograms and/or summaries. -func lintHistogramSummaryReserved(mf *dto.MetricFamily) []Problem { - // These rules do not apply to untyped metrics. - t := mf.GetType() - if t == dto.MetricType_UNTYPED { - return nil - } - - var problems []Problem - - isHistogram := t == dto.MetricType_HISTOGRAM - isSummary := t == dto.MetricType_SUMMARY - - n := mf.GetName() - - if !isHistogram && strings.HasSuffix(n, "_bucket") { - problems = append(problems, newProblem(mf, `non-histogram metrics should not have "_bucket" suffix`)) - } - if !isHistogram && !isSummary && strings.HasSuffix(n, "_count") { - problems = append(problems, newProblem(mf, `non-histogram and non-summary metrics should not have "_count" suffix`)) - } - if !isHistogram && !isSummary && strings.HasSuffix(n, "_sum") { - problems = append(problems, newProblem(mf, `non-histogram and non-summary metrics should not have "_sum" suffix`)) - } - - for _, m := range mf.GetMetric() { - for _, l := range m.GetLabel() { - ln := l.GetName() - - if !isHistogram && ln == "le" { - problems = append(problems, newProblem(mf, `non-histogram metrics should not have "le" label`)) - } - if !isSummary && ln == "quantile" { - problems = append(problems, newProblem(mf, `non-summary metrics should not have "quantile" label`)) - } + for _, fn := range defaultValidations { + errs := fn(mf) + for _, err := range errs { + problems = append(problems, newProblem(mf, err.Error())) } } - return problems -} - -// lintMetricTypeInName detects when metric types are included in the metric name. -func lintMetricTypeInName(mf *dto.MetricFamily) []Problem { - var problems []Problem - n := strings.ToLower(mf.GetName()) - - for i, t := range dto.MetricType_name { - if i == int32(dto.MetricType_UNTYPED) { - continue - } - - typename := strings.ToLower(t) - if strings.Contains(n, "_"+typename+"_") || strings.HasSuffix(n, "_"+typename) { - problems = append(problems, newProblem(mf, fmt.Sprintf(`metric name should not include type '%s'`, typename))) - } - } - return problems -} - -// lintReservedChars detects colons in metric names. -func lintReservedChars(mf *dto.MetricFamily) []Problem { - var problems []Problem - if strings.Contains(mf.GetName(), ":") { - problems = append(problems, newProblem(mf, "metric names should not contain ':'")) - } - return problems -} - -var camelCase = regexp.MustCompile(`[a-z][A-Z]`) - -// lintCamelCase detects metric names and label names written in camelCase. -func lintCamelCase(mf *dto.MetricFamily) []Problem { - var problems []Problem - if camelCase.FindString(mf.GetName()) != "" { - problems = append(problems, newProblem(mf, "metric names should be written in 'snake_case' not 'camelCase'")) - } - - for _, m := range mf.GetMetric() { - for _, l := range m.GetLabel() { - if camelCase.FindString(l.GetName()) != "" { - problems = append(problems, newProblem(mf, "label names should be written in 'snake_case' not 'camelCase'")) + if l.customValidations != nil { + for _, fn := range l.customValidations { + errs := fn(mf) + for _, err := range errs { + problems = append(problems, newProblem(mf, err.Error())) } } } - return problems -} -// lintUnitAbbreviations detects abbreviated units in the metric name. -func lintUnitAbbreviations(mf *dto.MetricFamily) []Problem { - var problems []Problem - n := strings.ToLower(mf.GetName()) - for _, s := range unitAbbreviations { - if strings.Contains(n, "_"+s+"_") || strings.HasSuffix(n, "_"+s) { - problems = append(problems, newProblem(mf, "metric names should not contain abbreviated units")) - } - } + // TODO(mdlayher): lint rules for specific metrics types. return problems } - -// metricUnits attempts to detect known unit types used as part of a metric name, -// e.g. "foo_bytes_total" or "bar_baz_milligrams". -func metricUnits(m string) (unit, base string, ok bool) { - ss := strings.Split(m, "_") - - for unit, base := range units { - // Also check for "no prefix". - for _, p := range append(unitPrefixes, "") { - for _, s := range ss { - // Attempt to explicitly match a known unit with a known prefix, - // as some words may look like "units" when matching suffix. - // - // As an example, "thermometers" should not match "meters", but - // "kilometers" should. - if s == p+unit { - return p + unit, base, true - } - } - } - } - - return "", "", false -} - -// Units and their possible prefixes recognized by this library. More can be -// added over time as needed. -var ( - // map a unit to the appropriate base unit. - units = map[string]string{ - // Base units. - "amperes": "amperes", - "bytes": "bytes", - "celsius": "celsius", // Also allow Celsius because it is common in typical Prometheus use cases. - "grams": "grams", - "joules": "joules", - "kelvin": "kelvin", // SI base unit, used in special cases (e.g. color temperature, scientific measurements). - "meters": "meters", // Both American and international spelling permitted. - "metres": "metres", - "seconds": "seconds", - "volts": "volts", - - // Non base units. - // Time. - "minutes": "seconds", - "hours": "seconds", - "days": "seconds", - "weeks": "seconds", - // Temperature. - "kelvins": "kelvin", - "fahrenheit": "celsius", - "rankine": "celsius", - // Length. - "inches": "meters", - "yards": "meters", - "miles": "meters", - // Bytes. - "bits": "bytes", - // Energy. - "calories": "joules", - // Mass. - "pounds": "grams", - "ounces": "grams", - } - - unitPrefixes = []string{ - "pico", - "nano", - "micro", - "milli", - "centi", - "deci", - "deca", - "hecto", - "kilo", - "kibi", - "mega", - "mibi", - "giga", - "gibi", - "tera", - "tebi", - "peta", - "pebi", - } - - // Common abbreviations that we'd like to discourage. - unitAbbreviations = []string{ - "s", - "ms", - "us", - "ns", - "sec", - "b", - "kb", - "mb", - "gb", - "tb", - "pb", - "m", - "h", - "d", - } -) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validation.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validation.go new file mode 100644 index 000000000..f52ad9eab --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validation.go @@ -0,0 +1,33 @@ +// Copyright 2020 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 promlint + +import ( + dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/client_golang/prometheus/testutil/promlint/validations" +) + +type Validation = func(mf *dto.MetricFamily) []error + +var defaultValidations = []Validation{ + validations.LintHelp, + validations.LintMetricUnits, + validations.LintCounter, + validations.LintHistogramSummaryReserved, + validations.LintMetricTypeInName, + validations.LintReservedChars, + validations.LintCamelCase, + validations.LintUnitAbbreviations, +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/counter_validations.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/counter_validations.go new file mode 100644 index 000000000..f2c2c3905 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/counter_validations.go @@ -0,0 +1,40 @@ +// Copyright 2020 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 validations + +import ( + "errors" + "strings" + + dto "github.com/prometheus/client_model/go" +) + +// LintCounter detects issues specific to counters, as well as patterns that should +// only be used with counters. +func LintCounter(mf *dto.MetricFamily) []error { + var problems []error + + isCounter := mf.GetType() == dto.MetricType_COUNTER + isUntyped := mf.GetType() == dto.MetricType_UNTYPED + hasTotalSuffix := strings.HasSuffix(mf.GetName(), "_total") + + switch { + case isCounter && !hasTotalSuffix: + problems = append(problems, errors.New(`counter metrics should have "_total" suffix`)) + case !isUntyped && !isCounter && hasTotalSuffix: + problems = append(problems, errors.New(`non-counter metrics should not have "_total" suffix`)) + } + + return problems +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/generic_name_validations.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/generic_name_validations.go new file mode 100644 index 000000000..bc8dbd1e1 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/generic_name_validations.go @@ -0,0 +1,101 @@ +// Copyright 2020 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 validations + +import ( + "errors" + "fmt" + "regexp" + "strings" + + dto "github.com/prometheus/client_model/go" +) + +var camelCase = regexp.MustCompile(`[a-z][A-Z]`) + +// LintMetricUnits detects issues with metric unit names. +func LintMetricUnits(mf *dto.MetricFamily) []error { + var problems []error + + unit, base, ok := metricUnits(*mf.Name) + if !ok { + // No known units detected. + return nil + } + + // Unit is already a base unit. + if unit == base { + return nil + } + + problems = append(problems, fmt.Errorf("use base unit %q instead of %q", base, unit)) + + return problems +} + +// LintMetricTypeInName detects when metric types are included in the metric name. +func LintMetricTypeInName(mf *dto.MetricFamily) []error { + var problems []error + n := strings.ToLower(mf.GetName()) + + for i, t := range dto.MetricType_name { + if i == int32(dto.MetricType_UNTYPED) { + continue + } + + typename := strings.ToLower(t) + if strings.Contains(n, "_"+typename+"_") || strings.HasSuffix(n, "_"+typename) { + problems = append(problems, fmt.Errorf(`metric name should not include type '%s'`, typename)) + } + } + return problems +} + +// LintReservedChars detects colons in metric names. +func LintReservedChars(mf *dto.MetricFamily) []error { + var problems []error + if strings.Contains(mf.GetName(), ":") { + problems = append(problems, errors.New("metric names should not contain ':'")) + } + return problems +} + +// LintCamelCase detects metric names and label names written in camelCase. +func LintCamelCase(mf *dto.MetricFamily) []error { + var problems []error + if camelCase.FindString(mf.GetName()) != "" { + problems = append(problems, errors.New("metric names should be written in 'snake_case' not 'camelCase'")) + } + + for _, m := range mf.GetMetric() { + for _, l := range m.GetLabel() { + if camelCase.FindString(l.GetName()) != "" { + problems = append(problems, errors.New("label names should be written in 'snake_case' not 'camelCase'")) + } + } + } + return problems +} + +// LintUnitAbbreviations detects abbreviated units in the metric name. +func LintUnitAbbreviations(mf *dto.MetricFamily) []error { + var problems []error + n := strings.ToLower(mf.GetName()) + for _, s := range unitAbbreviations { + if strings.Contains(n, "_"+s+"_") || strings.HasSuffix(n, "_"+s) { + problems = append(problems, errors.New("metric names should not contain abbreviated units")) + } + } + return problems +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/help_validations.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/help_validations.go new file mode 100644 index 000000000..1df294468 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/help_validations.go @@ -0,0 +1,32 @@ +// Copyright 2020 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 validations + +import ( + "errors" + + dto "github.com/prometheus/client_model/go" +) + +// LintHelp detects issues related to the help text for a metric. +func LintHelp(mf *dto.MetricFamily) []error { + var problems []error + + // Expect all metrics to have help text available. + if mf.Help == nil { + problems = append(problems, errors.New("no help text")) + } + + return problems +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/histogram_validations.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/histogram_validations.go new file mode 100644 index 000000000..6564bdf36 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/histogram_validations.go @@ -0,0 +1,63 @@ +// Copyright 2020 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 validations + +import ( + "errors" + "strings" + + dto "github.com/prometheus/client_model/go" +) + +// LintHistogramSummaryReserved detects when other types of metrics use names or labels +// reserved for use by histograms and/or summaries. +func LintHistogramSummaryReserved(mf *dto.MetricFamily) []error { + // These rules do not apply to untyped metrics. + t := mf.GetType() + if t == dto.MetricType_UNTYPED { + return nil + } + + var problems []error + + isHistogram := t == dto.MetricType_HISTOGRAM + isSummary := t == dto.MetricType_SUMMARY + + n := mf.GetName() + + if !isHistogram && strings.HasSuffix(n, "_bucket") { + problems = append(problems, errors.New(`non-histogram metrics should not have "_bucket" suffix`)) + } + if !isHistogram && !isSummary && strings.HasSuffix(n, "_count") { + problems = append(problems, errors.New(`non-histogram and non-summary metrics should not have "_count" suffix`)) + } + if !isHistogram && !isSummary && strings.HasSuffix(n, "_sum") { + problems = append(problems, errors.New(`non-histogram and non-summary metrics should not have "_sum" suffix`)) + } + + for _, m := range mf.GetMetric() { + for _, l := range m.GetLabel() { + ln := l.GetName() + + if !isHistogram && ln == "le" { + problems = append(problems, errors.New(`non-histogram metrics should not have "le" label`)) + } + if !isSummary && ln == "quantile" { + problems = append(problems, errors.New(`non-summary metrics should not have "quantile" label`)) + } + } + } + + return problems +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/units.go b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/units.go new file mode 100644 index 000000000..967977d2b --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint/validations/units.go @@ -0,0 +1,118 @@ +// Copyright 2020 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 validations + +import "strings" + +// Units and their possible prefixes recognized by this library. More can be +// added over time as needed. +var ( + // map a unit to the appropriate base unit. + units = map[string]string{ + // Base units. + "amperes": "amperes", + "bytes": "bytes", + "celsius": "celsius", // Also allow Celsius because it is common in typical Prometheus use cases. + "grams": "grams", + "joules": "joules", + "kelvin": "kelvin", // SI base unit, used in special cases (e.g. color temperature, scientific measurements). + "meters": "meters", // Both American and international spelling permitted. + "metres": "metres", + "seconds": "seconds", + "volts": "volts", + + // Non base units. + // Time. + "minutes": "seconds", + "hours": "seconds", + "days": "seconds", + "weeks": "seconds", + // Temperature. + "kelvins": "kelvin", + "fahrenheit": "celsius", + "rankine": "celsius", + // Length. + "inches": "meters", + "yards": "meters", + "miles": "meters", + // Bytes. + "bits": "bytes", + // Energy. + "calories": "joules", + // Mass. + "pounds": "grams", + "ounces": "grams", + } + + unitPrefixes = []string{ + "pico", + "nano", + "micro", + "milli", + "centi", + "deci", + "deca", + "hecto", + "kilo", + "kibi", + "mega", + "mibi", + "giga", + "gibi", + "tera", + "tebi", + "peta", + "pebi", + } + + // Common abbreviations that we'd like to discourage. + unitAbbreviations = []string{ + "s", + "ms", + "us", + "ns", + "sec", + "b", + "kb", + "mb", + "gb", + "tb", + "pb", + "m", + "h", + "d", + } +) + +// metricUnits attempts to detect known unit types used as part of a metric name, +// e.g. "foo_bytes_total" or "bar_baz_milligrams". +func metricUnits(m string) (unit, base string, ok bool) { + ss := strings.Split(m, "_") + + for _, s := range ss { + if base, found := units[s]; found { + return s, base, true + } + + for _, p := range unitPrefixes { + if strings.HasPrefix(s, p) { + if base, found := units[s[len(p):]]; found { + return s, base, true + } + } + } + } + + return "", "", false +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go index f28a76f3a..52344fef5 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/timer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go @@ -23,7 +23,9 @@ type Timer struct { } // NewTimer creates a new Timer. The provided Observer is used to observe a -// duration in seconds. Timer is usually used to time a function call in the +// duration in seconds. If the Observer implements ExemplarObserver, passing exemplar +// later on will be also supported. +// Timer is usually used to time a function call in the // following way: // // func TimeMe() { @@ -31,6 +33,14 @@ type Timer struct { // defer timer.ObserveDuration() // // Do actual work. // } +// +// or +// +// func TimeMeWithExemplar() { +// timer := NewTimer(myHistogram) +// defer timer.ObserveDurationWithExemplar(exemplar) +// // Do actual work. +// } func NewTimer(o Observer) *Timer { return &Timer{ begin: time.Now(), @@ -53,3 +63,19 @@ func (t *Timer) ObserveDuration() time.Duration { } return d } + +// ObserveDurationWithExemplar is like ObserveDuration, but it will also +// observe exemplar with the duration unless exemplar is nil or provided Observer can't +// be casted to ExemplarObserver. +func (t *Timer) ObserveDurationWithExemplar(exemplar Labels) time.Duration { + d := time.Since(t.begin) + eo, ok := t.observer.(ExemplarObserver) + if ok && exemplar != nil { + eo.ObserveWithExemplar(d.Seconds(), exemplar) + return d + } + if t.observer != nil { + t.observer.Observe(d.Seconds()) + } + return d +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/value.go b/vendor/github.com/prometheus/client_golang/prometheus/value.go index 2d3abc1cb..cc23011fa 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/value.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/value.go @@ -14,18 +14,17 @@ package prometheus import ( + "errors" "fmt" "sort" "time" "unicode/utf8" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/types/known/timestamppb" - "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" ) // ValueType is an enumeration of metric types that represent a simple value. @@ -93,7 +92,7 @@ func (v *valueFunc) Desc() *Desc { } func (v *valueFunc) Write(out *dto.Metric) error { - return populateMetric(v.valType, v.function(), v.labelPairs, nil, out) + return populateMetric(v.valType, v.function(), v.labelPairs, nil, out, nil) } // NewConstMetric returns a metric with one fixed value that cannot be @@ -107,12 +106,12 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues if desc.err != nil { return nil, desc.err } - if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { + if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil { return nil, err } metric := &dto.Metric{} - if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil { + if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, nil); err != nil { return nil, err } @@ -132,6 +131,43 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal return m } +// NewConstMetricWithCreatedTimestamp does the same thing as NewConstMetric, but generates Counters +// with created timestamp set and returns an error for other metric types. +func NewConstMetricWithCreatedTimestamp(desc *Desc, valueType ValueType, value float64, ct time.Time, labelValues ...string) (Metric, error) { + if desc.err != nil { + return nil, desc.err + } + if err := validateLabelValues(labelValues, len(desc.variableLabels.names)); err != nil { + return nil, err + } + switch valueType { + case CounterValue: + break + default: + return nil, errors.New("created timestamps are only supported for counters") + } + + metric := &dto.Metric{} + if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric, timestamppb.New(ct)); err != nil { + return nil, err + } + + return &constMetric{ + desc: desc, + metric: metric, + }, nil +} + +// MustNewConstMetricWithCreatedTimestamp is a version of NewConstMetricWithCreatedTimestamp that panics where +// NewConstMetricWithCreatedTimestamp would have returned an error. +func MustNewConstMetricWithCreatedTimestamp(desc *Desc, valueType ValueType, value float64, ct time.Time, labelValues ...string) Metric { + m, err := NewConstMetricWithCreatedTimestamp(desc, valueType, value, ct, labelValues...) + if err != nil { + panic(err) + } + return m +} + type constMetric struct { desc *Desc metric *dto.Metric @@ -155,11 +191,12 @@ func populateMetric( labelPairs []*dto.LabelPair, e *dto.Exemplar, m *dto.Metric, + ct *timestamppb.Timestamp, ) error { m.Label = labelPairs switch t { case CounterValue: - m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e} + m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e, CreatedTimestamp: ct} case GaugeValue: m.Gauge = &dto.Gauge{Value: proto.Float64(v)} case UntypedValue: @@ -178,19 +215,19 @@ func populateMetric( // This function is only needed for custom Metric implementations. See MetricVec // example. func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair { - totalLen := len(desc.variableLabels) + len(desc.constLabelPairs) + totalLen := len(desc.variableLabels.names) + len(desc.constLabelPairs) if totalLen == 0 { // Super fast path. return nil } - if len(desc.variableLabels) == 0 { + if len(desc.variableLabels.names) == 0 { // Moderately fast path. return desc.constLabelPairs } labelPairs := make([]*dto.LabelPair, 0, totalLen) - for i, n := range desc.variableLabels { + for i, l := range desc.variableLabels.names { labelPairs = append(labelPairs, &dto.LabelPair{ - Name: proto.String(n), + Name: proto.String(l), Value: proto.String(labelValues[i]), }) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec.go b/vendor/github.com/prometheus/client_golang/prometheus/vec.go index 7ae322590..955cfd59f 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/vec.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/vec.go @@ -72,6 +72,8 @@ func NewMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *MetricVec { // with a performance overhead (for creating and processing the Labels map). // See also the CounterVec example. func (m *MetricVec) DeleteLabelValues(lvs ...string) bool { + lvs = constrainLabelValues(m.desc, lvs, m.curry) + h, err := m.hashLabelValues(lvs) if err != nil { return false @@ -91,6 +93,9 @@ func (m *MetricVec) DeleteLabelValues(lvs ...string) bool { // This method is used for the same purpose as DeleteLabelValues(...string). See // there for pros and cons of the two methods. func (m *MetricVec) Delete(labels Labels) bool { + labels, closer := constrainLabels(m.desc, labels) + defer closer() + h, err := m.hashLabels(labels) if err != nil { return false @@ -106,6 +111,9 @@ func (m *MetricVec) Delete(labels Labels) bool { // Note that curried labels will never be matched if deleting from the curried vector. // To match curried labels with DeletePartialMatch, it must be called on the base vector. func (m *MetricVec) DeletePartialMatch(labels Labels) int { + labels, closer := constrainLabels(m.desc, labels) + defer closer() + return m.metricMap.deleteByLabels(labels, m.curry) } @@ -144,11 +152,11 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) { oldCurry = m.curry iCurry int ) - for i, label := range m.desc.variableLabels { - val, ok := labels[label] + for i, labelName := range m.desc.variableLabels.names { + val, ok := labels[labelName] if iCurry < len(oldCurry) && oldCurry[iCurry].index == i { if ok { - return nil, fmt.Errorf("label name %q is already curried", label) + return nil, fmt.Errorf("label name %q is already curried", labelName) } newCurry = append(newCurry, oldCurry[iCurry]) iCurry++ @@ -156,7 +164,10 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) { if !ok { continue // Label stays uncurried. } - newCurry = append(newCurry, curriedLabelValue{i, val}) + newCurry = append(newCurry, curriedLabelValue{ + i, + m.desc.variableLabels.constrain(labelName, val), + }) } } if l := len(oldCurry) + len(labels) - len(newCurry); l > 0 { @@ -199,6 +210,7 @@ func (m *MetricVec) CurryWith(labels Labels) (*MetricVec, error) { // a wrapper around MetricVec, implementing a vector for a specific Metric // implementation, for example GaugeVec. func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) { + lvs = constrainLabelValues(m.desc, lvs, m.curry) h, err := m.hashLabelValues(lvs) if err != nil { return nil, err @@ -224,6 +236,9 @@ func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) { // around MetricVec, implementing a vector for a specific Metric implementation, // for example GaugeVec. func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) { + labels, closer := constrainLabels(m.desc, labels) + defer closer() + h, err := m.hashLabels(labels) if err != nil { return nil, err @@ -233,7 +248,7 @@ func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) { } func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) { - if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil { + if err := validateLabelValues(vals, len(m.desc.variableLabels.names)-len(m.curry)); err != nil { return 0, err } @@ -242,7 +257,7 @@ func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) { curry = m.curry iVals, iCurry int ) - for i := 0; i < len(m.desc.variableLabels); i++ { + for i := 0; i < len(m.desc.variableLabels.names); i++ { if iCurry < len(curry) && curry[iCurry].index == i { h = m.hashAdd(h, curry[iCurry].value) iCurry++ @@ -256,7 +271,7 @@ func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) { } func (m *MetricVec) hashLabels(labels Labels) (uint64, error) { - if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil { + if err := validateValuesInLabels(labels, len(m.desc.variableLabels.names)-len(m.curry)); err != nil { return 0, err } @@ -265,17 +280,17 @@ func (m *MetricVec) hashLabels(labels Labels) (uint64, error) { curry = m.curry iCurry int ) - for i, label := range m.desc.variableLabels { - val, ok := labels[label] + for i, labelName := range m.desc.variableLabels.names { + val, ok := labels[labelName] if iCurry < len(curry) && curry[iCurry].index == i { if ok { - return 0, fmt.Errorf("label name %q is already curried", label) + return 0, fmt.Errorf("label name %q is already curried", labelName) } h = m.hashAdd(h, curry[iCurry].value) iCurry++ } else { if !ok { - return 0, fmt.Errorf("label name %q missing in label map", label) + return 0, fmt.Errorf("label name %q missing in label map", labelName) } h = m.hashAdd(h, val) } @@ -453,7 +468,7 @@ func valueMatchesVariableOrCurriedValue(targetValue string, index int, values [] func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool { for l, v := range labels { // Check if the target label exists in our metrics and get the index. - varLabelIndex, validLabel := indexOf(l, desc.variableLabels) + varLabelIndex, validLabel := indexOf(l, desc.variableLabels.names) if validLabel { // Check the value of that label against the target value. // We don't consider curried values in partial matches. @@ -597,7 +612,7 @@ func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabe return false } iCurry := 0 - for i, k := range desc.variableLabels { + for i, k := range desc.variableLabels.names { if iCurry < len(curry) && curry[iCurry].index == i { if values[i] != curry[iCurry].value { return false @@ -615,7 +630,7 @@ func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabe func extractLabelValues(desc *Desc, labels Labels, curry []curriedLabelValue) []string { labelValues := make([]string, len(labels)+len(curry)) iCurry := 0 - for i, k := range desc.variableLabels { + for i, k := range desc.variableLabels.names { if iCurry < len(curry) && curry[iCurry].index == i { labelValues[i] = curry[iCurry].value iCurry++ @@ -640,3 +655,55 @@ func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string { } return labelValues } + +var labelsPool = &sync.Pool{ + New: func() interface{} { + return make(Labels) + }, +} + +func constrainLabels(desc *Desc, labels Labels) (Labels, func()) { + if len(desc.variableLabels.labelConstraints) == 0 { + // Fast path when there's no constraints + return labels, func() {} + } + + constrainedLabels := labelsPool.Get().(Labels) + for l, v := range labels { + constrainedLabels[l] = desc.variableLabels.constrain(l, v) + } + + return constrainedLabels, func() { + for k := range constrainedLabels { + delete(constrainedLabels, k) + } + labelsPool.Put(constrainedLabels) + } +} + +func constrainLabelValues(desc *Desc, lvs []string, curry []curriedLabelValue) []string { + if len(desc.variableLabels.labelConstraints) == 0 { + // Fast path when there's no constraints + return lvs + } + + constrainedValues := make([]string, len(lvs)) + var iCurry, iLVs int + for i := 0; i < len(lvs)+len(curry); i++ { + if iCurry < len(curry) && curry[iCurry].index == i { + iCurry++ + continue + } + + if i < len(desc.variableLabels.names) { + constrainedValues[iLVs] = desc.variableLabels.constrain( + desc.variableLabels.names[i], + lvs[iLVs], + ) + } else { + constrainedValues[iLVs] = lvs[iLVs] + } + iLVs++ + } + return constrainedValues +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vnext.go b/vendor/github.com/prometheus/client_golang/prometheus/vnext.go new file mode 100644 index 000000000..42bc3a8f0 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/vnext.go @@ -0,0 +1,23 @@ +// Copyright 2022 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 + +type v2 struct{} + +// V2 is a struct that can be referenced to access experimental API that might +// be present in v2 of client golang someday. It offers extended functionality +// of v1 with slightly changed API. It is acceptable to use some pieces from v1 +// and e.g `prometheus.NewGauge` and some from v2 e.g. `prometheus.V2.NewDesc` +// in the same codebase. +var V2 = v2{} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go index 1498ee144..25da157f1 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/wrap.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/wrap.go @@ -17,12 +17,10 @@ import ( "fmt" "sort" - //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/golang/protobuf/proto" + "github.com/prometheus/client_golang/prometheus/internal" dto "github.com/prometheus/client_model/go" - - "github.com/prometheus/client_golang/prometheus/internal" + "google.golang.org/protobuf/proto" ) // WrapRegistererWith returns a Registerer wrapping the provided @@ -206,7 +204,7 @@ func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc { constLabels[ln] = lv } // NewDesc will do remaining validations. - newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels) + newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels) // Propagate errors if there was any. This will override any errer // created by NewDesc above, i.e. earlier errors get precedence. if desc.err != nil { diff --git a/vendor/github.com/prometheus/client_model/go/metrics.pb.go b/vendor/github.com/prometheus/client_model/go/metrics.pb.go index 35904ea19..cee360db7 100644 --- a/vendor/github.com/prometheus/client_model/go/metrics.pb.go +++ b/vendor/github.com/prometheus/client_model/go/metrics.pb.go @@ -1,25 +1,38 @@ +// Copyright 2013 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.20.3 // source: io/prometheus/client/metrics.proto package io_prometheus_client import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - timestamp "github.com/golang/protobuf/ptypes/timestamp" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) type MetricType int32 @@ -38,23 +51,25 @@ const ( MetricType_GAUGE_HISTOGRAM MetricType = 5 ) -var MetricType_name = map[int32]string{ - 0: "COUNTER", - 1: "GAUGE", - 2: "SUMMARY", - 3: "UNTYPED", - 4: "HISTOGRAM", - 5: "GAUGE_HISTOGRAM", -} - -var MetricType_value = map[string]int32{ - "COUNTER": 0, - "GAUGE": 1, - "SUMMARY": 2, - "UNTYPED": 3, - "HISTOGRAM": 4, - "GAUGE_HISTOGRAM": 5, -} +// Enum value maps for MetricType. +var ( + MetricType_name = map[int32]string{ + 0: "COUNTER", + 1: "GAUGE", + 2: "SUMMARY", + 3: "UNTYPED", + 4: "HISTOGRAM", + 5: "GAUGE_HISTOGRAM", + } + MetricType_value = map[string]int32{ + "COUNTER": 0, + "GAUGE": 1, + "SUMMARY": 2, + "UNTYPED": 3, + "HISTOGRAM": 4, + "GAUGE_HISTOGRAM": 5, + } +) func (x MetricType) Enum() *MetricType { p := new(MetricType) @@ -63,449 +78,546 @@ func (x MetricType) Enum() *MetricType { } func (x MetricType) String() string { - return proto.EnumName(MetricType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *MetricType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(MetricType_value, data, "MetricType") +func (MetricType) Descriptor() protoreflect.EnumDescriptor { + return file_io_prometheus_client_metrics_proto_enumTypes[0].Descriptor() +} + +func (MetricType) Type() protoreflect.EnumType { + return &file_io_prometheus_client_metrics_proto_enumTypes[0] +} + +func (x MetricType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *MetricType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = MetricType(value) + *x = MetricType(num) return nil } +// Deprecated: Use MetricType.Descriptor instead. func (MetricType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{0} + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{0} } type LabelPair struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *LabelPair) Reset() { *m = LabelPair{} } -func (m *LabelPair) String() string { return proto.CompactTextString(m) } -func (*LabelPair) ProtoMessage() {} -func (*LabelPair) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{0} + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` } -func (m *LabelPair) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LabelPair.Unmarshal(m, b) -} -func (m *LabelPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LabelPair.Marshal(b, m, deterministic) -} -func (m *LabelPair) XXX_Merge(src proto.Message) { - xxx_messageInfo_LabelPair.Merge(m, src) +func (x *LabelPair) Reset() { + *x = LabelPair{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *LabelPair) XXX_Size() int { - return xxx_messageInfo_LabelPair.Size(m) + +func (x *LabelPair) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *LabelPair) XXX_DiscardUnknown() { - xxx_messageInfo_LabelPair.DiscardUnknown(m) + +func (*LabelPair) ProtoMessage() {} + +func (x *LabelPair) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_LabelPair proto.InternalMessageInfo +// Deprecated: Use LabelPair.ProtoReflect.Descriptor instead. +func (*LabelPair) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{0} +} -func (m *LabelPair) GetName() string { - if m != nil && m.Name != nil { - return *m.Name +func (x *LabelPair) GetName() string { + if x != nil && x.Name != nil { + return *x.Name } return "" } -func (m *LabelPair) GetValue() string { - if m != nil && m.Value != nil { - return *m.Value +func (x *LabelPair) GetValue() string { + if x != nil && x.Value != nil { + return *x.Value } return "" } type Gauge struct { - Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *Gauge) Reset() { *m = Gauge{} } -func (m *Gauge) String() string { return proto.CompactTextString(m) } -func (*Gauge) ProtoMessage() {} -func (*Gauge) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{1} + Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` } -func (m *Gauge) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Gauge.Unmarshal(m, b) -} -func (m *Gauge) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Gauge.Marshal(b, m, deterministic) -} -func (m *Gauge) XXX_Merge(src proto.Message) { - xxx_messageInfo_Gauge.Merge(m, src) +func (x *Gauge) Reset() { + *x = Gauge{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Gauge) XXX_Size() int { - return xxx_messageInfo_Gauge.Size(m) + +func (x *Gauge) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Gauge) XXX_DiscardUnknown() { - xxx_messageInfo_Gauge.DiscardUnknown(m) + +func (*Gauge) ProtoMessage() {} + +func (x *Gauge) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Gauge proto.InternalMessageInfo +// Deprecated: Use Gauge.ProtoReflect.Descriptor instead. +func (*Gauge) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{1} +} -func (m *Gauge) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value +func (x *Gauge) GetValue() float64 { + if x != nil && x.Value != nil { + return *x.Value } return 0 } type Counter struct { - Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` - Exemplar *Exemplar `protobuf:"bytes,2,opt,name=exemplar" json:"exemplar,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *Counter) Reset() { *m = Counter{} } -func (m *Counter) String() string { return proto.CompactTextString(m) } -func (*Counter) ProtoMessage() {} -func (*Counter) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{2} + Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` + Exemplar *Exemplar `protobuf:"bytes,2,opt,name=exemplar" json:"exemplar,omitempty"` + CreatedTimestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_timestamp,json=createdTimestamp" json:"created_timestamp,omitempty"` } -func (m *Counter) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Counter.Unmarshal(m, b) -} -func (m *Counter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Counter.Marshal(b, m, deterministic) -} -func (m *Counter) XXX_Merge(src proto.Message) { - xxx_messageInfo_Counter.Merge(m, src) +func (x *Counter) Reset() { + *x = Counter{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Counter) XXX_Size() int { - return xxx_messageInfo_Counter.Size(m) + +func (x *Counter) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Counter) XXX_DiscardUnknown() { - xxx_messageInfo_Counter.DiscardUnknown(m) + +func (*Counter) ProtoMessage() {} + +func (x *Counter) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Counter proto.InternalMessageInfo +// Deprecated: Use Counter.ProtoReflect.Descriptor instead. +func (*Counter) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{2} +} -func (m *Counter) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value +func (x *Counter) GetValue() float64 { + if x != nil && x.Value != nil { + return *x.Value } return 0 } -func (m *Counter) GetExemplar() *Exemplar { - if m != nil { - return m.Exemplar +func (x *Counter) GetExemplar() *Exemplar { + if x != nil { + return x.Exemplar } return nil } -type Quantile struct { - Quantile *float64 `protobuf:"fixed64,1,opt,name=quantile" json:"quantile,omitempty"` - Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *Counter) GetCreatedTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.CreatedTimestamp + } + return nil } -func (m *Quantile) Reset() { *m = Quantile{} } -func (m *Quantile) String() string { return proto.CompactTextString(m) } -func (*Quantile) ProtoMessage() {} -func (*Quantile) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{3} -} +type Quantile struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *Quantile) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Quantile.Unmarshal(m, b) -} -func (m *Quantile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Quantile.Marshal(b, m, deterministic) + Quantile *float64 `protobuf:"fixed64,1,opt,name=quantile" json:"quantile,omitempty"` + Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` } -func (m *Quantile) XXX_Merge(src proto.Message) { - xxx_messageInfo_Quantile.Merge(m, src) + +func (x *Quantile) Reset() { + *x = Quantile{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Quantile) XXX_Size() int { - return xxx_messageInfo_Quantile.Size(m) + +func (x *Quantile) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Quantile) XXX_DiscardUnknown() { - xxx_messageInfo_Quantile.DiscardUnknown(m) + +func (*Quantile) ProtoMessage() {} + +func (x *Quantile) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Quantile proto.InternalMessageInfo +// Deprecated: Use Quantile.ProtoReflect.Descriptor instead. +func (*Quantile) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{3} +} -func (m *Quantile) GetQuantile() float64 { - if m != nil && m.Quantile != nil { - return *m.Quantile +func (x *Quantile) GetQuantile() float64 { + if x != nil && x.Quantile != nil { + return *x.Quantile } return 0 } -func (m *Quantile) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value +func (x *Quantile) GetValue() float64 { + if x != nil && x.Value != nil { + return *x.Value } return 0 } type Summary struct { - SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"` - SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` - Quantile []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"` + SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` + Quantile []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"` + CreatedTimestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_timestamp,json=createdTimestamp" json:"created_timestamp,omitempty"` +} + +func (x *Summary) Reset() { + *x = Summary{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Summary) Reset() { *m = Summary{} } -func (m *Summary) String() string { return proto.CompactTextString(m) } -func (*Summary) ProtoMessage() {} -func (*Summary) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{4} +func (x *Summary) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Summary) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Summary.Unmarshal(m, b) -} -func (m *Summary) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Summary.Marshal(b, m, deterministic) -} -func (m *Summary) XXX_Merge(src proto.Message) { - xxx_messageInfo_Summary.Merge(m, src) -} -func (m *Summary) XXX_Size() int { - return xxx_messageInfo_Summary.Size(m) -} -func (m *Summary) XXX_DiscardUnknown() { - xxx_messageInfo_Summary.DiscardUnknown(m) +func (*Summary) ProtoMessage() {} + +func (x *Summary) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Summary proto.InternalMessageInfo +// Deprecated: Use Summary.ProtoReflect.Descriptor instead. +func (*Summary) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{4} +} -func (m *Summary) GetSampleCount() uint64 { - if m != nil && m.SampleCount != nil { - return *m.SampleCount +func (x *Summary) GetSampleCount() uint64 { + if x != nil && x.SampleCount != nil { + return *x.SampleCount } return 0 } -func (m *Summary) GetSampleSum() float64 { - if m != nil && m.SampleSum != nil { - return *m.SampleSum +func (x *Summary) GetSampleSum() float64 { + if x != nil && x.SampleSum != nil { + return *x.SampleSum } return 0 } -func (m *Summary) GetQuantile() []*Quantile { - if m != nil { - return m.Quantile +func (x *Summary) GetQuantile() []*Quantile { + if x != nil { + return x.Quantile } return nil } -type Untyped struct { - Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *Summary) GetCreatedTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.CreatedTimestamp + } + return nil } -func (m *Untyped) Reset() { *m = Untyped{} } -func (m *Untyped) String() string { return proto.CompactTextString(m) } -func (*Untyped) ProtoMessage() {} -func (*Untyped) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{5} -} +type Untyped struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *Untyped) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Untyped.Unmarshal(m, b) -} -func (m *Untyped) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Untyped.Marshal(b, m, deterministic) + Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"` } -func (m *Untyped) XXX_Merge(src proto.Message) { - xxx_messageInfo_Untyped.Merge(m, src) + +func (x *Untyped) Reset() { + *x = Untyped{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Untyped) XXX_Size() int { - return xxx_messageInfo_Untyped.Size(m) + +func (x *Untyped) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Untyped) XXX_DiscardUnknown() { - xxx_messageInfo_Untyped.DiscardUnknown(m) + +func (*Untyped) ProtoMessage() {} + +func (x *Untyped) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Untyped proto.InternalMessageInfo +// Deprecated: Use Untyped.ProtoReflect.Descriptor instead. +func (*Untyped) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{5} +} -func (m *Untyped) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value +func (x *Untyped) GetValue() float64 { + if x != nil && x.Value != nil { + return *x.Value } return 0 } type Histogram struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count,json=sampleCount" json:"sample_count,omitempty"` - SampleCountFloat *float64 `protobuf:"fixed64,4,opt,name=sample_count_float,json=sampleCountFloat" json:"sample_count_float,omitempty"` + SampleCountFloat *float64 `protobuf:"fixed64,4,opt,name=sample_count_float,json=sampleCountFloat" json:"sample_count_float,omitempty"` // Overrides sample_count if > 0. SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` // Buckets for the conventional histogram. - Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"` + Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"` // Ordered in increasing order of upper_bound, +Inf bucket is optional. + CreatedTimestamp *timestamppb.Timestamp `protobuf:"bytes,15,opt,name=created_timestamp,json=createdTimestamp" json:"created_timestamp,omitempty"` // schema defines the bucket schema. Currently, valid numbers are -4 <= n <= 8. // They are all for base-2 bucket schemas, where 1 is a bucket boundary in each case, and // then each power of two is divided into 2^n logarithmic buckets. // Or in other words, each bucket boundary is the previous boundary times 2^(2^-n). // In the future, more bucket schemas may be added using numbers < -4 or > 8. Schema *int32 `protobuf:"zigzag32,5,opt,name=schema" json:"schema,omitempty"` - ZeroThreshold *float64 `protobuf:"fixed64,6,opt,name=zero_threshold,json=zeroThreshold" json:"zero_threshold,omitempty"` - ZeroCount *uint64 `protobuf:"varint,7,opt,name=zero_count,json=zeroCount" json:"zero_count,omitempty"` - ZeroCountFloat *float64 `protobuf:"fixed64,8,opt,name=zero_count_float,json=zeroCountFloat" json:"zero_count_float,omitempty"` + ZeroThreshold *float64 `protobuf:"fixed64,6,opt,name=zero_threshold,json=zeroThreshold" json:"zero_threshold,omitempty"` // Breadth of the zero bucket. + ZeroCount *uint64 `protobuf:"varint,7,opt,name=zero_count,json=zeroCount" json:"zero_count,omitempty"` // Count in zero bucket. + ZeroCountFloat *float64 `protobuf:"fixed64,8,opt,name=zero_count_float,json=zeroCountFloat" json:"zero_count_float,omitempty"` // Overrides sb_zero_count if > 0. // Negative buckets for the native histogram. NegativeSpan []*BucketSpan `protobuf:"bytes,9,rep,name=negative_span,json=negativeSpan" json:"negative_span,omitempty"` // Use either "negative_delta" or "negative_count", the former for // regular histograms with integer counts, the latter for float // histograms. - NegativeDelta []int64 `protobuf:"zigzag64,10,rep,name=negative_delta,json=negativeDelta" json:"negative_delta,omitempty"` - NegativeCount []float64 `protobuf:"fixed64,11,rep,name=negative_count,json=negativeCount" json:"negative_count,omitempty"` + NegativeDelta []int64 `protobuf:"zigzag64,10,rep,name=negative_delta,json=negativeDelta" json:"negative_delta,omitempty"` // Count delta of each bucket compared to previous one (or to zero for 1st bucket). + NegativeCount []float64 `protobuf:"fixed64,11,rep,name=negative_count,json=negativeCount" json:"negative_count,omitempty"` // Absolute count of each bucket. // Positive buckets for the native histogram. + // Use a no-op span (offset 0, length 0) for a native histogram without any + // observations yet and with a zero_threshold of 0. Otherwise, it would be + // indistinguishable from a classic histogram. PositiveSpan []*BucketSpan `protobuf:"bytes,12,rep,name=positive_span,json=positiveSpan" json:"positive_span,omitempty"` // Use either "positive_delta" or "positive_count", the former for // regular histograms with integer counts, the latter for float // histograms. - PositiveDelta []int64 `protobuf:"zigzag64,13,rep,name=positive_delta,json=positiveDelta" json:"positive_delta,omitempty"` - PositiveCount []float64 `protobuf:"fixed64,14,rep,name=positive_count,json=positiveCount" json:"positive_count,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + PositiveDelta []int64 `protobuf:"zigzag64,13,rep,name=positive_delta,json=positiveDelta" json:"positive_delta,omitempty"` // Count delta of each bucket compared to previous one (or to zero for 1st bucket). + PositiveCount []float64 `protobuf:"fixed64,14,rep,name=positive_count,json=positiveCount" json:"positive_count,omitempty"` // Absolute count of each bucket. } -func (m *Histogram) Reset() { *m = Histogram{} } -func (m *Histogram) String() string { return proto.CompactTextString(m) } -func (*Histogram) ProtoMessage() {} -func (*Histogram) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{6} +func (x *Histogram) Reset() { + *x = Histogram{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Histogram) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Histogram.Unmarshal(m, b) -} -func (m *Histogram) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Histogram.Marshal(b, m, deterministic) -} -func (m *Histogram) XXX_Merge(src proto.Message) { - xxx_messageInfo_Histogram.Merge(m, src) +func (x *Histogram) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Histogram) XXX_Size() int { - return xxx_messageInfo_Histogram.Size(m) -} -func (m *Histogram) XXX_DiscardUnknown() { - xxx_messageInfo_Histogram.DiscardUnknown(m) + +func (*Histogram) ProtoMessage() {} + +func (x *Histogram) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Histogram proto.InternalMessageInfo +// Deprecated: Use Histogram.ProtoReflect.Descriptor instead. +func (*Histogram) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{6} +} -func (m *Histogram) GetSampleCount() uint64 { - if m != nil && m.SampleCount != nil { - return *m.SampleCount +func (x *Histogram) GetSampleCount() uint64 { + if x != nil && x.SampleCount != nil { + return *x.SampleCount } return 0 } -func (m *Histogram) GetSampleCountFloat() float64 { - if m != nil && m.SampleCountFloat != nil { - return *m.SampleCountFloat +func (x *Histogram) GetSampleCountFloat() float64 { + if x != nil && x.SampleCountFloat != nil { + return *x.SampleCountFloat } return 0 } -func (m *Histogram) GetSampleSum() float64 { - if m != nil && m.SampleSum != nil { - return *m.SampleSum +func (x *Histogram) GetSampleSum() float64 { + if x != nil && x.SampleSum != nil { + return *x.SampleSum } return 0 } -func (m *Histogram) GetBucket() []*Bucket { - if m != nil { - return m.Bucket +func (x *Histogram) GetBucket() []*Bucket { + if x != nil { + return x.Bucket + } + return nil +} + +func (x *Histogram) GetCreatedTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.CreatedTimestamp } return nil } -func (m *Histogram) GetSchema() int32 { - if m != nil && m.Schema != nil { - return *m.Schema +func (x *Histogram) GetSchema() int32 { + if x != nil && x.Schema != nil { + return *x.Schema } return 0 } -func (m *Histogram) GetZeroThreshold() float64 { - if m != nil && m.ZeroThreshold != nil { - return *m.ZeroThreshold +func (x *Histogram) GetZeroThreshold() float64 { + if x != nil && x.ZeroThreshold != nil { + return *x.ZeroThreshold } return 0 } -func (m *Histogram) GetZeroCount() uint64 { - if m != nil && m.ZeroCount != nil { - return *m.ZeroCount +func (x *Histogram) GetZeroCount() uint64 { + if x != nil && x.ZeroCount != nil { + return *x.ZeroCount } return 0 } -func (m *Histogram) GetZeroCountFloat() float64 { - if m != nil && m.ZeroCountFloat != nil { - return *m.ZeroCountFloat +func (x *Histogram) GetZeroCountFloat() float64 { + if x != nil && x.ZeroCountFloat != nil { + return *x.ZeroCountFloat } return 0 } -func (m *Histogram) GetNegativeSpan() []*BucketSpan { - if m != nil { - return m.NegativeSpan +func (x *Histogram) GetNegativeSpan() []*BucketSpan { + if x != nil { + return x.NegativeSpan } return nil } -func (m *Histogram) GetNegativeDelta() []int64 { - if m != nil { - return m.NegativeDelta +func (x *Histogram) GetNegativeDelta() []int64 { + if x != nil { + return x.NegativeDelta } return nil } -func (m *Histogram) GetNegativeCount() []float64 { - if m != nil { - return m.NegativeCount +func (x *Histogram) GetNegativeCount() []float64 { + if x != nil { + return x.NegativeCount } return nil } -func (m *Histogram) GetPositiveSpan() []*BucketSpan { - if m != nil { - return m.PositiveSpan +func (x *Histogram) GetPositiveSpan() []*BucketSpan { + if x != nil { + return x.PositiveSpan } return nil } -func (m *Histogram) GetPositiveDelta() []int64 { - if m != nil { - return m.PositiveDelta +func (x *Histogram) GetPositiveDelta() []int64 { + if x != nil { + return x.PositiveDelta } return nil } -func (m *Histogram) GetPositiveCount() []float64 { - if m != nil { - return m.PositiveCount +func (x *Histogram) GetPositiveCount() []float64 { + if x != nil { + return x.PositiveCount } return nil } @@ -513,64 +625,72 @@ func (m *Histogram) GetPositiveCount() []float64 { // A Bucket of a conventional histogram, each of which is treated as // an individual counter-like time series by Prometheus. type Bucket struct { - CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count,json=cumulativeCount" json:"cumulative_count,omitempty"` - CumulativeCountFloat *float64 `protobuf:"fixed64,4,opt,name=cumulative_count_float,json=cumulativeCountFloat" json:"cumulative_count_float,omitempty"` - UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count,json=cumulativeCount" json:"cumulative_count,omitempty"` // Cumulative in increasing order. + CumulativeCountFloat *float64 `protobuf:"fixed64,4,opt,name=cumulative_count_float,json=cumulativeCountFloat" json:"cumulative_count_float,omitempty"` // Overrides cumulative_count if > 0. + UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"` // Inclusive. Exemplar *Exemplar `protobuf:"bytes,3,opt,name=exemplar" json:"exemplar,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` } -func (m *Bucket) Reset() { *m = Bucket{} } -func (m *Bucket) String() string { return proto.CompactTextString(m) } -func (*Bucket) ProtoMessage() {} -func (*Bucket) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{7} +func (x *Bucket) Reset() { + *x = Bucket{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Bucket) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Bucket.Unmarshal(m, b) -} -func (m *Bucket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Bucket.Marshal(b, m, deterministic) -} -func (m *Bucket) XXX_Merge(src proto.Message) { - xxx_messageInfo_Bucket.Merge(m, src) +func (x *Bucket) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Bucket) XXX_Size() int { - return xxx_messageInfo_Bucket.Size(m) -} -func (m *Bucket) XXX_DiscardUnknown() { - xxx_messageInfo_Bucket.DiscardUnknown(m) + +func (*Bucket) ProtoMessage() {} + +func (x *Bucket) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Bucket proto.InternalMessageInfo +// Deprecated: Use Bucket.ProtoReflect.Descriptor instead. +func (*Bucket) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{7} +} -func (m *Bucket) GetCumulativeCount() uint64 { - if m != nil && m.CumulativeCount != nil { - return *m.CumulativeCount +func (x *Bucket) GetCumulativeCount() uint64 { + if x != nil && x.CumulativeCount != nil { + return *x.CumulativeCount } return 0 } -func (m *Bucket) GetCumulativeCountFloat() float64 { - if m != nil && m.CumulativeCountFloat != nil { - return *m.CumulativeCountFloat +func (x *Bucket) GetCumulativeCountFloat() float64 { + if x != nil && x.CumulativeCountFloat != nil { + return *x.CumulativeCountFloat } return 0 } -func (m *Bucket) GetUpperBound() float64 { - if m != nil && m.UpperBound != nil { - return *m.UpperBound +func (x *Bucket) GetUpperBound() float64 { + if x != nil && x.UpperBound != nil { + return *x.UpperBound } return 0 } -func (m *Bucket) GetExemplar() *Exemplar { - if m != nil { - return m.Exemplar +func (x *Bucket) GetExemplar() *Exemplar { + if x != nil { + return x.Exemplar } return nil } @@ -582,333 +702,675 @@ func (m *Bucket) GetExemplar() *Exemplar { // structured here (with all the buckets in a single array separate // from the Spans). type BucketSpan struct { - Offset *int32 `protobuf:"zigzag32,1,opt,name=offset" json:"offset,omitempty"` - Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *BucketSpan) Reset() { *m = BucketSpan{} } -func (m *BucketSpan) String() string { return proto.CompactTextString(m) } -func (*BucketSpan) ProtoMessage() {} -func (*BucketSpan) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{8} + Offset *int32 `protobuf:"zigzag32,1,opt,name=offset" json:"offset,omitempty"` // Gap to previous span, or starting point for 1st span (which can be negative). + Length *uint32 `protobuf:"varint,2,opt,name=length" json:"length,omitempty"` // Length of consecutive buckets. } -func (m *BucketSpan) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BucketSpan.Unmarshal(m, b) -} -func (m *BucketSpan) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BucketSpan.Marshal(b, m, deterministic) -} -func (m *BucketSpan) XXX_Merge(src proto.Message) { - xxx_messageInfo_BucketSpan.Merge(m, src) +func (x *BucketSpan) Reset() { + *x = BucketSpan{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *BucketSpan) XXX_Size() int { - return xxx_messageInfo_BucketSpan.Size(m) + +func (x *BucketSpan) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *BucketSpan) XXX_DiscardUnknown() { - xxx_messageInfo_BucketSpan.DiscardUnknown(m) + +func (*BucketSpan) ProtoMessage() {} + +func (x *BucketSpan) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_BucketSpan proto.InternalMessageInfo +// Deprecated: Use BucketSpan.ProtoReflect.Descriptor instead. +func (*BucketSpan) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{8} +} -func (m *BucketSpan) GetOffset() int32 { - if m != nil && m.Offset != nil { - return *m.Offset +func (x *BucketSpan) GetOffset() int32 { + if x != nil && x.Offset != nil { + return *x.Offset } return 0 } -func (m *BucketSpan) GetLength() uint32 { - if m != nil && m.Length != nil { - return *m.Length +func (x *BucketSpan) GetLength() uint32 { + if x != nil && x.Length != nil { + return *x.Length } return 0 } type Exemplar struct { - Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` - Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` - Timestamp *timestamp.Timestamp `protobuf:"bytes,3,opt,name=timestamp" json:"timestamp,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *Exemplar) Reset() { *m = Exemplar{} } -func (m *Exemplar) String() string { return proto.CompactTextString(m) } -func (*Exemplar) ProtoMessage() {} -func (*Exemplar) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{9} + Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` + Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=timestamp" json:"timestamp,omitempty"` // OpenMetrics-style. } -func (m *Exemplar) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Exemplar.Unmarshal(m, b) -} -func (m *Exemplar) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Exemplar.Marshal(b, m, deterministic) -} -func (m *Exemplar) XXX_Merge(src proto.Message) { - xxx_messageInfo_Exemplar.Merge(m, src) +func (x *Exemplar) Reset() { + *x = Exemplar{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Exemplar) XXX_Size() int { - return xxx_messageInfo_Exemplar.Size(m) + +func (x *Exemplar) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Exemplar) XXX_DiscardUnknown() { - xxx_messageInfo_Exemplar.DiscardUnknown(m) + +func (*Exemplar) ProtoMessage() {} + +func (x *Exemplar) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Exemplar proto.InternalMessageInfo +// Deprecated: Use Exemplar.ProtoReflect.Descriptor instead. +func (*Exemplar) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{9} +} -func (m *Exemplar) GetLabel() []*LabelPair { - if m != nil { - return m.Label +func (x *Exemplar) GetLabel() []*LabelPair { + if x != nil { + return x.Label } return nil } -func (m *Exemplar) GetValue() float64 { - if m != nil && m.Value != nil { - return *m.Value +func (x *Exemplar) GetValue() float64 { + if x != nil && x.Value != nil { + return *x.Value } return 0 } -func (m *Exemplar) GetTimestamp() *timestamp.Timestamp { - if m != nil { - return m.Timestamp +func (x *Exemplar) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp } return nil } type Metric struct { - Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` - Gauge *Gauge `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"` - Counter *Counter `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"` - Summary *Summary `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"` - Untyped *Untyped `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"` - Histogram *Histogram `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"` - TimestampMs *int64 `protobuf:"varint,6,opt,name=timestamp_ms,json=timestampMs" json:"timestamp_ms,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Metric) Reset() { *m = Metric{} } -func (m *Metric) String() string { return proto.CompactTextString(m) } -func (*Metric) ProtoMessage() {} -func (*Metric) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{10} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` + Gauge *Gauge `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"` + Counter *Counter `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"` + Summary *Summary `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"` + Untyped *Untyped `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"` + Histogram *Histogram `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"` + TimestampMs *int64 `protobuf:"varint,6,opt,name=timestamp_ms,json=timestampMs" json:"timestamp_ms,omitempty"` +} + +func (x *Metric) Reset() { + *x = Metric{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Metric) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Metric.Unmarshal(m, b) -} -func (m *Metric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Metric.Marshal(b, m, deterministic) -} -func (m *Metric) XXX_Merge(src proto.Message) { - xxx_messageInfo_Metric.Merge(m, src) +func (x *Metric) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Metric) XXX_Size() int { - return xxx_messageInfo_Metric.Size(m) -} -func (m *Metric) XXX_DiscardUnknown() { - xxx_messageInfo_Metric.DiscardUnknown(m) + +func (*Metric) ProtoMessage() {} + +func (x *Metric) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Metric proto.InternalMessageInfo +// Deprecated: Use Metric.ProtoReflect.Descriptor instead. +func (*Metric) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{10} +} -func (m *Metric) GetLabel() []*LabelPair { - if m != nil { - return m.Label +func (x *Metric) GetLabel() []*LabelPair { + if x != nil { + return x.Label } return nil } -func (m *Metric) GetGauge() *Gauge { - if m != nil { - return m.Gauge +func (x *Metric) GetGauge() *Gauge { + if x != nil { + return x.Gauge } return nil } -func (m *Metric) GetCounter() *Counter { - if m != nil { - return m.Counter +func (x *Metric) GetCounter() *Counter { + if x != nil { + return x.Counter } return nil } -func (m *Metric) GetSummary() *Summary { - if m != nil { - return m.Summary +func (x *Metric) GetSummary() *Summary { + if x != nil { + return x.Summary } return nil } -func (m *Metric) GetUntyped() *Untyped { - if m != nil { - return m.Untyped +func (x *Metric) GetUntyped() *Untyped { + if x != nil { + return x.Untyped } return nil } -func (m *Metric) GetHistogram() *Histogram { - if m != nil { - return m.Histogram +func (x *Metric) GetHistogram() *Histogram { + if x != nil { + return x.Histogram } return nil } -func (m *Metric) GetTimestampMs() int64 { - if m != nil && m.TimestampMs != nil { - return *m.TimestampMs +func (x *Metric) GetTimestampMs() int64 { + if x != nil && x.TimestampMs != nil { + return *x.TimestampMs } return 0 } type MetricFamily struct { - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"` - Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"` - Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *MetricFamily) Reset() { *m = MetricFamily{} } -func (m *MetricFamily) String() string { return proto.CompactTextString(m) } -func (*MetricFamily) ProtoMessage() {} -func (*MetricFamily) Descriptor() ([]byte, []int) { - return fileDescriptor_d1e5ddb18987a258, []int{11} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"` + Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"` + Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"` +} + +func (x *MetricFamily) Reset() { + *x = MetricFamily{} + if protoimpl.UnsafeEnabled { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *MetricFamily) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MetricFamily.Unmarshal(m, b) -} -func (m *MetricFamily) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MetricFamily.Marshal(b, m, deterministic) -} -func (m *MetricFamily) XXX_Merge(src proto.Message) { - xxx_messageInfo_MetricFamily.Merge(m, src) +func (x *MetricFamily) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *MetricFamily) XXX_Size() int { - return xxx_messageInfo_MetricFamily.Size(m) -} -func (m *MetricFamily) XXX_DiscardUnknown() { - xxx_messageInfo_MetricFamily.DiscardUnknown(m) + +func (*MetricFamily) ProtoMessage() {} + +func (x *MetricFamily) ProtoReflect() protoreflect.Message { + mi := &file_io_prometheus_client_metrics_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_MetricFamily proto.InternalMessageInfo +// Deprecated: Use MetricFamily.ProtoReflect.Descriptor instead. +func (*MetricFamily) Descriptor() ([]byte, []int) { + return file_io_prometheus_client_metrics_proto_rawDescGZIP(), []int{11} +} -func (m *MetricFamily) GetName() string { - if m != nil && m.Name != nil { - return *m.Name +func (x *MetricFamily) GetName() string { + if x != nil && x.Name != nil { + return *x.Name } return "" } -func (m *MetricFamily) GetHelp() string { - if m != nil && m.Help != nil { - return *m.Help +func (x *MetricFamily) GetHelp() string { + if x != nil && x.Help != nil { + return *x.Help } return "" } -func (m *MetricFamily) GetType() MetricType { - if m != nil && m.Type != nil { - return *m.Type +func (x *MetricFamily) GetType() MetricType { + if x != nil && x.Type != nil { + return *x.Type } return MetricType_COUNTER } -func (m *MetricFamily) GetMetric() []*Metric { - if m != nil { - return m.Metric +func (x *MetricFamily) GetMetric() []*Metric { + if x != nil { + return x.Metric } return nil } -func init() { - proto.RegisterEnum("io.prometheus.client.MetricType", MetricType_name, MetricType_value) - proto.RegisterType((*LabelPair)(nil), "io.prometheus.client.LabelPair") - proto.RegisterType((*Gauge)(nil), "io.prometheus.client.Gauge") - proto.RegisterType((*Counter)(nil), "io.prometheus.client.Counter") - proto.RegisterType((*Quantile)(nil), "io.prometheus.client.Quantile") - proto.RegisterType((*Summary)(nil), "io.prometheus.client.Summary") - proto.RegisterType((*Untyped)(nil), "io.prometheus.client.Untyped") - proto.RegisterType((*Histogram)(nil), "io.prometheus.client.Histogram") - proto.RegisterType((*Bucket)(nil), "io.prometheus.client.Bucket") - proto.RegisterType((*BucketSpan)(nil), "io.prometheus.client.BucketSpan") - proto.RegisterType((*Exemplar)(nil), "io.prometheus.client.Exemplar") - proto.RegisterType((*Metric)(nil), "io.prometheus.client.Metric") - proto.RegisterType((*MetricFamily)(nil), "io.prometheus.client.MetricFamily") -} - -func init() { - proto.RegisterFile("io/prometheus/client/metrics.proto", fileDescriptor_d1e5ddb18987a258) -} - -var fileDescriptor_d1e5ddb18987a258 = []byte{ - // 896 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x8e, 0xdb, 0x44, - 0x18, 0xc5, 0x9b, 0x5f, 0x7f, 0xd9, 0x6c, 0xd3, 0x61, 0x55, 0x59, 0x0b, 0xcb, 0x06, 0x4b, 0x48, - 0x0b, 0x42, 0x8e, 0x40, 0x5b, 0x81, 0x0a, 0x5c, 0xec, 0xb6, 0xe9, 0x16, 0x89, 0xb4, 0x65, 0x92, - 0x5c, 0x14, 0x2e, 0xac, 0x49, 0x32, 0xeb, 0x58, 0x78, 0x3c, 0xc6, 0x1e, 0x57, 0x2c, 0x2f, 0xc0, - 0x35, 0xaf, 0xc0, 0xc3, 0xf0, 0x22, 0x3c, 0x08, 0x68, 0xfe, 0xec, 0xdd, 0xe2, 0x94, 0xd2, 0x3b, - 0x7f, 0x67, 0xce, 0xf7, 0xcd, 0x39, 0xe3, 0xc9, 0x71, 0xc0, 0x8f, 0xf9, 0x24, 0xcb, 0x39, 0xa3, - 0x62, 0x4b, 0xcb, 0x62, 0xb2, 0x4e, 0x62, 0x9a, 0x8a, 0x09, 0xa3, 0x22, 0x8f, 0xd7, 0x45, 0x90, - 0xe5, 0x5c, 0x70, 0x74, 0x18, 0xf3, 0xa0, 0xe6, 0x04, 0x9a, 0x73, 0x74, 0x12, 0x71, 0x1e, 0x25, - 0x74, 0xa2, 0x38, 0xab, 0xf2, 0x6a, 0x22, 0x62, 0x46, 0x0b, 0x41, 0x58, 0xa6, 0xdb, 0xfc, 0xfb, - 0xe0, 0x7e, 0x47, 0x56, 0x34, 0x79, 0x4e, 0xe2, 0x1c, 0x21, 0x68, 0xa7, 0x84, 0x51, 0xcf, 0x19, - 0x3b, 0xa7, 0x2e, 0x56, 0xcf, 0xe8, 0x10, 0x3a, 0x2f, 0x49, 0x52, 0x52, 0x6f, 0x4f, 0x81, 0xba, - 0xf0, 0x8f, 0xa1, 0x73, 0x49, 0xca, 0xe8, 0xc6, 0xb2, 0xec, 0x71, 0xec, 0xf2, 0x8f, 0xd0, 0x7b, - 0xc8, 0xcb, 0x54, 0xd0, 0xbc, 0x99, 0x80, 0x1e, 0x40, 0x9f, 0xfe, 0x42, 0x59, 0x96, 0x90, 0x5c, - 0x0d, 0x1e, 0x7c, 0xfe, 0x41, 0xd0, 0x64, 0x20, 0x98, 0x1a, 0x16, 0xae, 0xf8, 0xfe, 0xd7, 0xd0, - 0xff, 0xbe, 0x24, 0xa9, 0x88, 0x13, 0x8a, 0x8e, 0xa0, 0xff, 0xb3, 0x79, 0x36, 0x1b, 0x54, 0xf5, - 0x6d, 0xe5, 0x95, 0xb4, 0xdf, 0x1c, 0xe8, 0xcd, 0x4b, 0xc6, 0x48, 0x7e, 0x8d, 0x3e, 0x84, 0xfd, - 0x82, 0xb0, 0x2c, 0xa1, 0xe1, 0x5a, 0xaa, 0x55, 0x13, 0xda, 0x78, 0xa0, 0x31, 0x65, 0x00, 0x1d, - 0x03, 0x18, 0x4a, 0x51, 0x32, 0x33, 0xc9, 0xd5, 0xc8, 0xbc, 0x64, 0xd2, 0x47, 0xb5, 0x7f, 0x6b, - 0xdc, 0xda, 0xed, 0xc3, 0x2a, 0xae, 0xf5, 0xf9, 0x27, 0xd0, 0x5b, 0xa6, 0xe2, 0x3a, 0xa3, 0x9b, - 0x1d, 0xa7, 0xf8, 0x57, 0x1b, 0xdc, 0x27, 0x71, 0x21, 0x78, 0x94, 0x13, 0xf6, 0x26, 0x62, 0x3f, - 0x05, 0x74, 0x93, 0x12, 0x5e, 0x25, 0x9c, 0x08, 0xaf, 0xad, 0x66, 0x8e, 0x6e, 0x10, 0x1f, 0x4b, - 0xfc, 0xbf, 0xac, 0x9d, 0x41, 0x77, 0x55, 0xae, 0x7f, 0xa2, 0xc2, 0x18, 0x7b, 0xbf, 0xd9, 0xd8, - 0x85, 0xe2, 0x60, 0xc3, 0x45, 0xf7, 0xa0, 0x5b, 0xac, 0xb7, 0x94, 0x11, 0xaf, 0x33, 0x76, 0x4e, - 0xef, 0x62, 0x53, 0xa1, 0x8f, 0xe0, 0xe0, 0x57, 0x9a, 0xf3, 0x50, 0x6c, 0x73, 0x5a, 0x6c, 0x79, - 0xb2, 0xf1, 0xba, 0x6a, 0xc3, 0xa1, 0x44, 0x17, 0x16, 0x94, 0x9a, 0x14, 0x4d, 0x5b, 0xec, 0x29, - 0x8b, 0xae, 0x44, 0xb4, 0xc1, 0x53, 0x18, 0xd5, 0xcb, 0xc6, 0x5e, 0x5f, 0xcd, 0x39, 0xa8, 0x48, - 0xda, 0xdc, 0x14, 0x86, 0x29, 0x8d, 0x88, 0x88, 0x5f, 0xd2, 0xb0, 0xc8, 0x48, 0xea, 0xb9, 0xca, - 0xc4, 0xf8, 0x75, 0x26, 0xe6, 0x19, 0x49, 0xf1, 0xbe, 0x6d, 0x93, 0x95, 0x94, 0x5d, 0x8d, 0xd9, - 0xd0, 0x44, 0x10, 0x0f, 0xc6, 0xad, 0x53, 0x84, 0xab, 0xe1, 0x8f, 0x24, 0x78, 0x8b, 0xa6, 0xa5, - 0x0f, 0xc6, 0x2d, 0xe9, 0xce, 0xa2, 0x5a, 0xfe, 0x14, 0x86, 0x19, 0x2f, 0xe2, 0x5a, 0xd4, 0xfe, - 0x9b, 0x8a, 0xb2, 0x6d, 0x56, 0x54, 0x35, 0x46, 0x8b, 0x1a, 0x6a, 0x51, 0x16, 0xad, 0x44, 0x55, - 0x34, 0x2d, 0xea, 0x40, 0x8b, 0xb2, 0xa8, 0x12, 0xe5, 0xff, 0xe9, 0x40, 0x57, 0x6f, 0x85, 0x3e, - 0x86, 0xd1, 0xba, 0x64, 0x65, 0x72, 0xd3, 0x88, 0xbe, 0x66, 0x77, 0x6a, 0x5c, 0x5b, 0x39, 0x83, - 0x7b, 0xaf, 0x52, 0x6f, 0x5d, 0xb7, 0xc3, 0x57, 0x1a, 0xf4, 0x5b, 0x39, 0x81, 0x41, 0x99, 0x65, - 0x34, 0x0f, 0x57, 0xbc, 0x4c, 0x37, 0xe6, 0xce, 0x81, 0x82, 0x2e, 0x24, 0x72, 0x2b, 0x17, 0x5a, - 0xff, 0x3b, 0x17, 0xa0, 0x3e, 0x32, 0x79, 0x11, 0xf9, 0xd5, 0x55, 0x41, 0xb5, 0x83, 0xbb, 0xd8, - 0x54, 0x12, 0x4f, 0x68, 0x1a, 0x89, 0xad, 0xda, 0x7d, 0x88, 0x4d, 0xe5, 0xff, 0xee, 0x40, 0xdf, - 0x0e, 0x45, 0xf7, 0xa1, 0x93, 0xc8, 0x54, 0xf4, 0x1c, 0xf5, 0x82, 0x4e, 0x9a, 0x35, 0x54, 0xc1, - 0x89, 0x35, 0xbb, 0x39, 0x71, 0xd0, 0x97, 0xe0, 0x56, 0xa9, 0x6b, 0x4c, 0x1d, 0x05, 0x3a, 0x97, - 0x03, 0x9b, 0xcb, 0xc1, 0xc2, 0x32, 0x70, 0x4d, 0xf6, 0xff, 0xde, 0x83, 0xee, 0x4c, 0xa5, 0xfc, - 0xdb, 0x2a, 0xfa, 0x0c, 0x3a, 0x91, 0xcc, 0x69, 0x13, 0xb2, 0xef, 0x35, 0xb7, 0xa9, 0x28, 0xc7, - 0x9a, 0x89, 0xbe, 0x80, 0xde, 0x5a, 0x67, 0xb7, 0x11, 0x7b, 0xdc, 0xdc, 0x64, 0x02, 0x1e, 0x5b, - 0xb6, 0x6c, 0x2c, 0x74, 0xb0, 0xaa, 0x3b, 0xb0, 0xb3, 0xd1, 0xa4, 0x2f, 0xb6, 0x6c, 0xd9, 0x58, - 0xea, 0x20, 0x54, 0xa1, 0xb1, 0xb3, 0xd1, 0xa4, 0x25, 0xb6, 0x6c, 0xf4, 0x0d, 0xb8, 0x5b, 0x9b, - 0x8f, 0x2a, 0x2c, 0x76, 0x1e, 0x4c, 0x15, 0xa3, 0xb8, 0xee, 0x90, 0x89, 0x5a, 0x9d, 0x75, 0xc8, - 0x0a, 0x95, 0x48, 0x2d, 0x3c, 0xa8, 0xb0, 0x59, 0xe1, 0xff, 0xe1, 0xc0, 0xbe, 0x7e, 0x03, 0x8f, - 0x09, 0x8b, 0x93, 0xeb, 0xc6, 0x4f, 0x24, 0x82, 0xf6, 0x96, 0x26, 0x99, 0xf9, 0x42, 0xaa, 0x67, - 0x74, 0x06, 0x6d, 0xa9, 0x51, 0x1d, 0xe1, 0xc1, 0xae, 0x5f, 0xb8, 0x9e, 0xbc, 0xb8, 0xce, 0x28, - 0x56, 0x6c, 0x99, 0xb9, 0xfa, 0xab, 0xee, 0xb5, 0x5f, 0x97, 0xb9, 0xba, 0x0f, 0x1b, 0xee, 0x27, - 0x2b, 0x80, 0x7a, 0x12, 0x1a, 0x40, 0xef, 0xe1, 0xb3, 0xe5, 0xd3, 0xc5, 0x14, 0x8f, 0xde, 0x41, - 0x2e, 0x74, 0x2e, 0xcf, 0x97, 0x97, 0xd3, 0x91, 0x23, 0xf1, 0xf9, 0x72, 0x36, 0x3b, 0xc7, 0x2f, - 0x46, 0x7b, 0xb2, 0x58, 0x3e, 0x5d, 0xbc, 0x78, 0x3e, 0x7d, 0x34, 0x6a, 0xa1, 0x21, 0xb8, 0x4f, - 0xbe, 0x9d, 0x2f, 0x9e, 0x5d, 0xe2, 0xf3, 0xd9, 0xa8, 0x8d, 0xde, 0x85, 0x3b, 0xaa, 0x27, 0xac, - 0xc1, 0xce, 0x05, 0x86, 0xc6, 0x3f, 0x18, 0x3f, 0x3c, 0x88, 0x62, 0xb1, 0x2d, 0x57, 0xc1, 0x9a, - 0xb3, 0x7f, 0xff, 0x45, 0x09, 0x19, 0xdf, 0xd0, 0x64, 0x12, 0xf1, 0xaf, 0x62, 0x1e, 0xd6, 0xab, - 0xa1, 0x5e, 0xfd, 0x27, 0x00, 0x00, 0xff, 0xff, 0x16, 0x77, 0x81, 0x98, 0xd7, 0x08, 0x00, 0x00, +var File_io_prometheus_client_metrics_proto protoreflect.FileDescriptor + +var file_io_prometheus_client_metrics_proto_rawDesc = []byte{ + 0x0a, 0x22, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2f, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, + 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 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, 0x22, 0x35, 0x0a, 0x09, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x1d, 0x0a, 0x05, 0x47, 0x61, 0x75, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0xa4, 0x01, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, + 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x78, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x12, + 0x47, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3c, 0x0a, 0x08, 0x51, 0x75, 0x61, 0x6e, + 0x74, 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, + 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x73, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x53, 0x75, 0x6d, 0x12, 0x3a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, + 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x51, 0x75, + 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x6c, 0x65, + 0x12, 0x47, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x1f, 0x0a, 0x07, 0x55, 0x6e, 0x74, + 0x79, 0x70, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xac, 0x05, 0x0a, 0x09, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x10, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x12, 0x34, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, + 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x47, + 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x11, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, + 0x25, 0x0a, 0x0e, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x7a, 0x65, 0x72, 0x6f, 0x54, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x7a, 0x65, 0x72, 0x6f, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x0e, 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x12, + 0x45, 0x0a, 0x0d, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x6e, + 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, + 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x0c, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x12, 0x52, 0x0d, + 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x25, 0x0a, + 0x0e, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x0b, 0x20, 0x03, 0x28, 0x01, 0x52, 0x0d, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x45, 0x0a, 0x0d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x73, 0x70, 0x61, 0x6e, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x69, 0x6f, + 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x0c, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x0d, 0x20, + 0x03, 0x28, 0x12, 0x52, 0x0d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x6c, + 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x01, 0x52, 0x0d, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xc6, 0x01, 0x0a, 0x06, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, + 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x34, 0x0a, 0x16, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x14, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x70, 0x65, 0x72, 0x5f, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x75, 0x70, 0x70, 0x65, + 0x72, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, + 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, + 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x52, 0x08, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x72, 0x22, 0x3c, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x11, + 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x22, 0x91, 0x01, 0x0a, 0x08, 0x45, 0x78, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x72, 0x12, 0x35, 0x0a, + 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, + 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x22, 0xff, 0x02, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, + 0x35, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x50, 0x61, 0x69, 0x72, 0x52, + 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x31, 0x0a, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, + 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x61, 0x75, + 0x67, 0x65, 0x52, 0x05, 0x67, 0x61, 0x75, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e, + 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x12, 0x37, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, + 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x37, 0x0a, 0x07, 0x75, + 0x6e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, + 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x2e, 0x55, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x64, 0x52, 0x07, 0x75, 0x6e, 0x74, + 0x79, 0x70, 0x65, 0x64, 0x12, 0x3d, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, + 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x4d, 0x73, 0x22, 0xa2, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x65, 0x6c, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x12, + 0x34, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, + 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, + 0x74, 0x68, 0x65, 0x75, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2a, 0x62, 0x0a, 0x0a, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x55, + 0x4e, 0x54, 0x45, 0x52, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x47, 0x41, 0x55, 0x47, 0x45, 0x10, + 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x4d, 0x4d, 0x41, 0x52, 0x59, 0x10, 0x02, 0x12, 0x0b, + 0x0a, 0x07, 0x55, 0x4e, 0x54, 0x59, 0x50, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x48, + 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x47, 0x41, + 0x55, 0x47, 0x45, 0x5f, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x10, 0x05, 0x42, + 0x52, 0x0a, 0x14, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, + 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x2f, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x67, 0x6f, 0x3b, 0x69, + 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x5f, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, +} + +var ( + file_io_prometheus_client_metrics_proto_rawDescOnce sync.Once + file_io_prometheus_client_metrics_proto_rawDescData = file_io_prometheus_client_metrics_proto_rawDesc +) + +func file_io_prometheus_client_metrics_proto_rawDescGZIP() []byte { + file_io_prometheus_client_metrics_proto_rawDescOnce.Do(func() { + file_io_prometheus_client_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_io_prometheus_client_metrics_proto_rawDescData) + }) + return file_io_prometheus_client_metrics_proto_rawDescData +} + +var file_io_prometheus_client_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_io_prometheus_client_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_io_prometheus_client_metrics_proto_goTypes = []interface{}{ + (MetricType)(0), // 0: io.prometheus.client.MetricType + (*LabelPair)(nil), // 1: io.prometheus.client.LabelPair + (*Gauge)(nil), // 2: io.prometheus.client.Gauge + (*Counter)(nil), // 3: io.prometheus.client.Counter + (*Quantile)(nil), // 4: io.prometheus.client.Quantile + (*Summary)(nil), // 5: io.prometheus.client.Summary + (*Untyped)(nil), // 6: io.prometheus.client.Untyped + (*Histogram)(nil), // 7: io.prometheus.client.Histogram + (*Bucket)(nil), // 8: io.prometheus.client.Bucket + (*BucketSpan)(nil), // 9: io.prometheus.client.BucketSpan + (*Exemplar)(nil), // 10: io.prometheus.client.Exemplar + (*Metric)(nil), // 11: io.prometheus.client.Metric + (*MetricFamily)(nil), // 12: io.prometheus.client.MetricFamily + (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp +} +var file_io_prometheus_client_metrics_proto_depIdxs = []int32{ + 10, // 0: io.prometheus.client.Counter.exemplar:type_name -> io.prometheus.client.Exemplar + 13, // 1: io.prometheus.client.Counter.created_timestamp:type_name -> google.protobuf.Timestamp + 4, // 2: io.prometheus.client.Summary.quantile:type_name -> io.prometheus.client.Quantile + 13, // 3: io.prometheus.client.Summary.created_timestamp:type_name -> google.protobuf.Timestamp + 8, // 4: io.prometheus.client.Histogram.bucket:type_name -> io.prometheus.client.Bucket + 13, // 5: io.prometheus.client.Histogram.created_timestamp:type_name -> google.protobuf.Timestamp + 9, // 6: io.prometheus.client.Histogram.negative_span:type_name -> io.prometheus.client.BucketSpan + 9, // 7: io.prometheus.client.Histogram.positive_span:type_name -> io.prometheus.client.BucketSpan + 10, // 8: io.prometheus.client.Bucket.exemplar:type_name -> io.prometheus.client.Exemplar + 1, // 9: io.prometheus.client.Exemplar.label:type_name -> io.prometheus.client.LabelPair + 13, // 10: io.prometheus.client.Exemplar.timestamp:type_name -> google.protobuf.Timestamp + 1, // 11: io.prometheus.client.Metric.label:type_name -> io.prometheus.client.LabelPair + 2, // 12: io.prometheus.client.Metric.gauge:type_name -> io.prometheus.client.Gauge + 3, // 13: io.prometheus.client.Metric.counter:type_name -> io.prometheus.client.Counter + 5, // 14: io.prometheus.client.Metric.summary:type_name -> io.prometheus.client.Summary + 6, // 15: io.prometheus.client.Metric.untyped:type_name -> io.prometheus.client.Untyped + 7, // 16: io.prometheus.client.Metric.histogram:type_name -> io.prometheus.client.Histogram + 0, // 17: io.prometheus.client.MetricFamily.type:type_name -> io.prometheus.client.MetricType + 11, // 18: io.prometheus.client.MetricFamily.metric:type_name -> io.prometheus.client.Metric + 19, // [19:19] is the sub-list for method output_type + 19, // [19:19] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name +} + +func init() { file_io_prometheus_client_metrics_proto_init() } +func file_io_prometheus_client_metrics_proto_init() { + if File_io_prometheus_client_metrics_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_io_prometheus_client_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LabelPair); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Gauge); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Counter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Quantile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Summary); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Untyped); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Histogram); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BucketSpan); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Exemplar); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Metric); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_io_prometheus_client_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MetricFamily); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_io_prometheus_client_metrics_proto_rawDesc, + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_io_prometheus_client_metrics_proto_goTypes, + DependencyIndexes: file_io_prometheus_client_metrics_proto_depIdxs, + EnumInfos: file_io_prometheus_client_metrics_proto_enumTypes, + MessageInfos: file_io_prometheus_client_metrics_proto_msgTypes, + }.Build() + File_io_prometheus_client_metrics_proto = out.File + file_io_prometheus_client_metrics_proto_rawDesc = nil + file_io_prometheus_client_metrics_proto_goTypes = nil + file_io_prometheus_client_metrics_proto_depIdxs = nil } diff --git a/vendor/github.com/prometheus/common/expfmt/decode.go b/vendor/github.com/prometheus/common/expfmt/decode.go index 7657f841d..b2b89b017 100644 --- a/vendor/github.com/prometheus/common/expfmt/decode.go +++ b/vendor/github.com/prometheus/common/expfmt/decode.go @@ -14,6 +14,7 @@ package expfmt import ( + "bufio" "fmt" "io" "math" @@ -21,8 +22,8 @@ import ( "net/http" dto "github.com/prometheus/client_model/go" + "google.golang.org/protobuf/encoding/protodelim" - "github.com/matttproud/golang_protobuf_extensions/pbutil" "github.com/prometheus/common/model" ) @@ -44,7 +45,7 @@ func ResponseFormat(h http.Header) Format { mediatype, params, err := mime.ParseMediaType(ct) if err != nil { - return FmtUnknown + return fmtUnknown } const textType = "text/plain" @@ -52,28 +53,28 @@ func ResponseFormat(h http.Header) Format { switch mediatype { case ProtoType: if p, ok := params["proto"]; ok && p != ProtoProtocol { - return FmtUnknown + return fmtUnknown } if e, ok := params["encoding"]; ok && e != "delimited" { - return FmtUnknown + return fmtUnknown } - return FmtProtoDelim + return fmtProtoDelim case textType: if v, ok := params["version"]; ok && v != TextVersion { - return FmtUnknown + return fmtUnknown } - return FmtText + return fmtText } - return FmtUnknown + return fmtUnknown } // NewDecoder returns a new decoder based on the given input format. // If the input format does not imply otherwise, a text format decoder is returned. func NewDecoder(r io.Reader, format Format) Decoder { - switch format { - case FmtProtoDelim: + switch format.FormatType() { + case TypeProtoDelim: return &protoDecoder{r: r} } return &textDecoder{r: r} @@ -86,8 +87,10 @@ type protoDecoder struct { // Decode implements the Decoder interface. func (d *protoDecoder) Decode(v *dto.MetricFamily) error { - _, err := pbutil.ReadDelimited(d.r, v) - if err != nil { + opts := protodelim.UnmarshalOptions{ + MaxSize: -1, + } + if err := opts.UnmarshalFrom(bufio.NewReader(d.r), v); err != nil { return err } if !model.IsValidMetricName(model.LabelValue(v.GetName())) { @@ -115,32 +118,31 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error { // textDecoder implements the Decoder interface for the text protocol. type textDecoder struct { r io.Reader - p TextParser - fams []*dto.MetricFamily + fams map[string]*dto.MetricFamily + err error } // Decode implements the Decoder interface. func (d *textDecoder) Decode(v *dto.MetricFamily) error { - // TODO(fabxc): Wrap this as a line reader to make streaming safer. - if len(d.fams) == 0 { - // No cached metric families, read everything and parse metrics. - fams, err := d.p.TextToMetricFamilies(d.r) - if err != nil { - return err - } - if len(fams) == 0 { - return io.EOF - } - d.fams = make([]*dto.MetricFamily, 0, len(fams)) - for _, f := range fams { - d.fams = append(d.fams, f) + if d.err == nil { + // Read all metrics in one shot. + var p TextParser + d.fams, d.err = p.TextToMetricFamilies(d.r) + // If we don't get an error, store io.EOF for the end. + if d.err == nil { + d.err = io.EOF } } - - *v = *d.fams[0] - d.fams = d.fams[1:] - - return nil + // Pick off one MetricFamily per Decode until there's nothing left. + for key, fam := range d.fams { + v.Name = fam.Name + v.Help = fam.Help + v.Type = fam.Type + v.Metric = fam.Metric + delete(d.fams, key) + return nil + } + return d.err } // SampleDecoder wraps a Decoder to extract samples from the metric families diff --git a/vendor/github.com/prometheus/common/expfmt/encode.go b/vendor/github.com/prometheus/common/expfmt/encode.go index 64dc0eb40..8fd806184 100644 --- a/vendor/github.com/prometheus/common/expfmt/encode.go +++ b/vendor/github.com/prometheus/common/expfmt/encode.go @@ -18,9 +18,11 @@ import ( "io" "net/http" - "github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. - "github.com/matttproud/golang_protobuf_extensions/pbutil" + "google.golang.org/protobuf/encoding/protodelim" + "google.golang.org/protobuf/encoding/prototext" + "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg" + "github.com/prometheus/common/model" dto "github.com/prometheus/client_model/go" ) @@ -60,23 +62,32 @@ func (ec encoderCloser) Close() error { // as the support is still experimental. To include the option to negotiate // FmtOpenMetrics, use NegotiateOpenMetrics. func Negotiate(h http.Header) Format { + escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String()))) for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) { + if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" { + switch Format(escapeParam) { + case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues: + escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam)) + default: + // If the escaping parameter is unknown, ignore it. + } + } ver := ac.Params["version"] if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol { switch ac.Params["encoding"] { case "delimited": - return FmtProtoDelim + return fmtProtoDelim + escapingScheme case "text": - return FmtProtoText + return fmtProtoText + escapingScheme case "compact-text": - return FmtProtoCompact + return fmtProtoCompact + escapingScheme } } if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") { - return FmtText + return fmtText + escapingScheme } } - return FmtText + return fmtText + escapingScheme } // NegotiateIncludingOpenMetrics works like Negotiate but includes @@ -84,26 +95,40 @@ func Negotiate(h http.Header) Format { // temporary and will disappear once FmtOpenMetrics is fully supported and as // such may be negotiated by the normal Negotiate function. func NegotiateIncludingOpenMetrics(h http.Header) Format { + escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String()))) for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) { + if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" { + switch Format(escapeParam) { + case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues: + escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam)) + default: + // If the escaping parameter is unknown, ignore it. + } + } ver := ac.Params["version"] if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol { switch ac.Params["encoding"] { case "delimited": - return FmtProtoDelim + return fmtProtoDelim + escapingScheme case "text": - return FmtProtoText + return fmtProtoText + escapingScheme case "compact-text": - return FmtProtoCompact + return fmtProtoCompact + escapingScheme } } if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") { - return FmtText + return fmtText + escapingScheme } - if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion || ver == "") { - return FmtOpenMetrics + if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") { + switch ver { + case OpenMetricsVersion_1_0_0: + return fmtOpenMetrics_1_0_0 + escapingScheme + default: + return fmtOpenMetrics_0_0_1 + escapingScheme + } } } - return FmtText + return fmtText + escapingScheme } // NewEncoder returns a new encoder based on content type negotiation. All @@ -112,44 +137,48 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format { // for FmtOpenMetrics, but a future (breaking) release will add the Close method // to the Encoder interface directly. The current version of the Encoder // interface is kept for backwards compatibility. +// In cases where the Format does not allow for UTF-8 names, the global +// NameEscapingScheme will be applied. func NewEncoder(w io.Writer, format Format) Encoder { - switch format { - case FmtProtoDelim: + escapingScheme := format.ToEscapingScheme() + + switch format.FormatType() { + case TypeProtoDelim: return encoderCloser{ encode: func(v *dto.MetricFamily) error { - _, err := pbutil.WriteDelimited(w, v) + _, err := protodelim.MarshalTo(w, v) return err }, close: func() error { return nil }, } - case FmtProtoCompact: + case TypeProtoCompact: return encoderCloser{ encode: func(v *dto.MetricFamily) error { - _, err := fmt.Fprintln(w, v.String()) + _, err := fmt.Fprintln(w, model.EscapeMetricFamily(v, escapingScheme).String()) return err }, close: func() error { return nil }, } - case FmtProtoText: + case TypeProtoText: return encoderCloser{ encode: func(v *dto.MetricFamily) error { - _, err := fmt.Fprintln(w, proto.MarshalTextString(v)) + _, err := fmt.Fprintln(w, prototext.Format(model.EscapeMetricFamily(v, escapingScheme))) return err }, close: func() error { return nil }, } - case FmtText: + case TypeTextPlain: return encoderCloser{ encode: func(v *dto.MetricFamily) error { - _, err := MetricFamilyToText(w, v) + _, err := MetricFamilyToText(w, model.EscapeMetricFamily(v, escapingScheme)) return err }, close: func() error { return nil }, } - case FmtOpenMetrics: + case TypeOpenMetrics: return encoderCloser{ encode: func(v *dto.MetricFamily) error { - _, err := MetricFamilyToOpenMetrics(w, v) + _, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme)) return err }, close: func() error { diff --git a/vendor/github.com/prometheus/common/expfmt/expfmt.go b/vendor/github.com/prometheus/common/expfmt/expfmt.go index 0f176fa64..6fc9555e3 100644 --- a/vendor/github.com/prometheus/common/expfmt/expfmt.go +++ b/vendor/github.com/prometheus/common/expfmt/expfmt.go @@ -14,28 +14,154 @@ // Package expfmt contains tools for reading and writing Prometheus metrics. package expfmt +import ( + "strings" + + "github.com/prometheus/common/model" +) + // Format specifies the HTTP content type of the different wire protocols. type Format string -// Constants to assemble the Content-Type values for the different wire protocols. +// Constants to assemble the Content-Type values for the different wire +// protocols. The Content-Type strings here are all for the legacy exposition +// formats, where valid characters for metric names and label names are limited. +// Support for arbitrary UTF-8 characters in those names is already partially +// implemented in this module (see model.ValidationScheme), but to actually use +// it on the wire, new content-type strings will have to be agreed upon and +// added here. const ( - TextVersion = "0.0.4" - ProtoType = `application/vnd.google.protobuf` - ProtoProtocol = `io.prometheus.client.MetricFamily` - ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" - OpenMetricsType = `application/openmetrics-text` - OpenMetricsVersion = "0.0.1" - - // The Content-Type values for the different wire protocols. - FmtUnknown Format = `` - FmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8` - FmtProtoDelim Format = ProtoFmt + ` encoding=delimited` - FmtProtoText Format = ProtoFmt + ` encoding=text` - FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text` - FmtOpenMetrics Format = OpenMetricsType + `; version=` + OpenMetricsVersion + `; charset=utf-8` + TextVersion = "0.0.4" + ProtoType = `application/vnd.google.protobuf` + ProtoProtocol = `io.prometheus.client.MetricFamily` + protoFmt = ProtoType + "; proto=" + ProtoProtocol + ";" + OpenMetricsType = `application/openmetrics-text` + OpenMetricsVersion_0_0_1 = "0.0.1" + OpenMetricsVersion_1_0_0 = "1.0.0" + + // The Content-Type values for the different wire protocols. Note that these + // values are now unexported. If code was relying on comparisons to these + // constants, instead use FormatType(). + fmtUnknown Format = `` + fmtText Format = `text/plain; version=` + TextVersion + `; charset=utf-8` + fmtProtoDelim Format = protoFmt + ` encoding=delimited` + fmtProtoText Format = protoFmt + ` encoding=text` + fmtProtoCompact Format = protoFmt + ` encoding=compact-text` + fmtOpenMetrics_1_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_1_0_0 + `; charset=utf-8` + fmtOpenMetrics_0_0_1 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_0_0_1 + `; charset=utf-8` ) const ( hdrContentType = "Content-Type" hdrAccept = "Accept" ) + +// FormatType is a Go enum representing the overall category for the given +// Format. As the number of Format permutations increases, doing basic string +// comparisons are not feasible, so this enum captures the most useful +// high-level attribute of the Format string. +type FormatType int + +const ( + TypeUnknown = iota + TypeProtoCompact + TypeProtoDelim + TypeProtoText + TypeTextPlain + TypeOpenMetrics +) + +// NewFormat generates a new Format from the type provided. Mostly used for +// tests, most Formats should be generated as part of content negotiation in +// encode.go. +func NewFormat(t FormatType) Format { + switch t { + case TypeProtoCompact: + return fmtProtoCompact + case TypeProtoDelim: + return fmtProtoDelim + case TypeProtoText: + return fmtProtoText + case TypeTextPlain: + return fmtText + case TypeOpenMetrics: + return fmtOpenMetrics_1_0_0 + default: + return fmtUnknown + } +} + +// FormatType deduces an overall FormatType for the given format. +func (f Format) FormatType() FormatType { + toks := strings.Split(string(f), ";") + if len(toks) < 2 { + return TypeUnknown + } + + params := make(map[string]string) + for i, t := range toks { + if i == 0 { + continue + } + args := strings.Split(t, "=") + if len(args) != 2 { + continue + } + params[strings.TrimSpace(args[0])] = strings.TrimSpace(args[1]) + } + + switch strings.TrimSpace(toks[0]) { + case ProtoType: + if params["proto"] != ProtoProtocol { + return TypeUnknown + } + switch params["encoding"] { + case "delimited": + return TypeProtoDelim + case "text": + return TypeProtoText + case "compact-text": + return TypeProtoCompact + default: + return TypeUnknown + } + case OpenMetricsType: + if params["charset"] != "utf-8" { + return TypeUnknown + } + return TypeOpenMetrics + case "text/plain": + v, ok := params["version"] + if !ok { + return TypeTextPlain + } + if v == TextVersion { + return TypeTextPlain + } + return TypeUnknown + default: + return TypeUnknown + } +} + +// ToEscapingScheme returns an EscapingScheme depending on the Format. Iff the +// Format contains a escaping=allow-utf-8 term, it will select NoEscaping. If a valid +// "escaping" term exists, that will be used. Otherwise, the global default will +// be returned. +func (format Format) ToEscapingScheme() model.EscapingScheme { + for _, p := range strings.Split(string(format), ";") { + toks := strings.Split(p, "=") + if len(toks) != 2 { + continue + } + key, value := strings.TrimSpace(toks[0]), strings.TrimSpace(toks[1]) + if key == model.EscapingKey { + scheme, err := model.ToEscapingScheme(value) + if err != nil { + return model.NameEscapingScheme + } + return scheme + } + } + return model.NameEscapingScheme +} diff --git a/vendor/github.com/prometheus/common/expfmt/fuzz.go b/vendor/github.com/prometheus/common/expfmt/fuzz.go index f819e4f8b..dfac962a4 100644 --- a/vendor/github.com/prometheus/common/expfmt/fuzz.go +++ b/vendor/github.com/prometheus/common/expfmt/fuzz.go @@ -21,8 +21,8 @@ import "bytes" // Fuzz text metric parser with with github.com/dvyukov/go-fuzz: // -// go-fuzz-build github.com/prometheus/common/expfmt -// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz +// go-fuzz-build github.com/prometheus/common/expfmt +// go-fuzz -bin expfmt-fuzz.zip -workdir fuzz // // Further input samples should go in the folder fuzz/corpus. func Fuzz(in []byte) int { diff --git a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go index 9d94ae9ef..5622578ed 100644 --- a/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go +++ b/vendor/github.com/prometheus/common/expfmt/openmetrics_create.go @@ -35,6 +35,18 @@ import ( // sanity checks. If the input contains duplicate metrics or invalid metric or // label names, the conversion will result in invalid text format output. // +// If metric names conform to the legacy validation pattern, they will be placed +// outside the brackets in the traditional way, like `foo{}`. If the metric name +// fails the legacy validation check, it will be placed quoted inside the +// brackets: `{"foo"}`. As stated above, the input is assumed to be santized and +// no error will be thrown in this case. +// +// Similar to metric names, if label names conform to the legacy validation +// pattern, they will be unquoted as normal, like `foo{bar="baz"}`. If the label +// name fails the legacy validation check, it will be quoted: +// `foo{"bar"="baz"}`. As stated above, the input is assumed to be santized and +// no error will be thrown in this case. +// // This function fulfills the type 'expfmt.encoder'. // // Note that OpenMetrics requires a final `# EOF` line. Since this function acts @@ -46,20 +58,20 @@ import ( // missing features and peculiarities to avoid complications when switching from // Prometheus to OpenMetrics or vice versa: // -// - Counters are expected to have the `_total` suffix in their metric name. In -// the output, the suffix will be truncated from the `# TYPE` and `# HELP` -// line. A counter with a missing `_total` suffix is not an error. However, -// its type will be set to `unknown` in that case to avoid invalid OpenMetrics -// output. +// - Counters are expected to have the `_total` suffix in their metric name. In +// the output, the suffix will be truncated from the `# TYPE` and `# HELP` +// line. A counter with a missing `_total` suffix is not an error. However, +// its type will be set to `unknown` in that case to avoid invalid OpenMetrics +// output. // -// - No support for the following (optional) features: `# UNIT` line, `_created` -// line, info type, stateset type, gaugehistogram type. +// - No support for the following (optional) features: `# UNIT` line, `_created` +// line, info type, stateset type, gaugehistogram type. // -// - The size of exemplar labels is not checked (i.e. it's possible to create -// exemplars that are larger than allowed by the OpenMetrics specification). +// - The size of exemplar labels is not checked (i.e. it's possible to create +// exemplars that are larger than allowed by the OpenMetrics specification). // -// - The value of Counters is not checked. (OpenMetrics doesn't allow counters -// with a `NaN` value.) +// - The value of Counters is not checked. (OpenMetrics doesn't allow counters +// with a `NaN` value.) func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) { name := in.GetName() if name == "" { @@ -98,7 +110,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int if err != nil { return } - n, err = w.WriteString(shortName) + n, err = writeName(w, shortName) written += n if err != nil { return @@ -124,7 +136,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int if err != nil { return } - n, err = w.WriteString(shortName) + n, err = writeName(w, shortName) written += n if err != nil { return @@ -303,21 +315,9 @@ func writeOpenMetricsSample( floatValue float64, intValue uint64, useIntValue bool, exemplar *dto.Exemplar, ) (int, error) { - var written int - n, err := w.WriteString(name) - written += n - if err != nil { - return written, err - } - if suffix != "" { - n, err = w.WriteString(suffix) - written += n - if err != nil { - return written, err - } - } - n, err = writeOpenMetricsLabelPairs( - w, metric.Label, additionalLabelName, additionalLabelValue, + written := 0 + n, err := writeOpenMetricsNameAndLabelPairs( + w, name+suffix, metric.Label, additionalLabelName, additionalLabelValue, ) written += n if err != nil { @@ -365,27 +365,58 @@ func writeOpenMetricsSample( return written, nil } -// writeOpenMetricsLabelPairs works like writeOpenMetrics but formats the float -// in OpenMetrics style. -func writeOpenMetricsLabelPairs( +// writeOpenMetricsNameAndLabelPairs works like writeOpenMetricsSample but +// formats the float in OpenMetrics style. +func writeOpenMetricsNameAndLabelPairs( w enhancedWriter, + name string, in []*dto.LabelPair, additionalLabelName string, additionalLabelValue float64, ) (int, error) { - if len(in) == 0 && additionalLabelName == "" { - return 0, nil - } var ( - written int - separator byte = '{' + written int + separator byte = '{' + metricInsideBraces = false ) + + if name != "" { + // If the name does not pass the legacy validity check, we must put the + // metric name inside the braces, quoted. + if !model.IsValidLegacyMetricName(model.LabelValue(name)) { + metricInsideBraces = true + err := w.WriteByte(separator) + written++ + if err != nil { + return written, err + } + separator = ',' + } + + n, err := writeName(w, name) + written += n + if err != nil { + return written, err + } + } + + if len(in) == 0 && additionalLabelName == "" { + if metricInsideBraces { + err := w.WriteByte('}') + written++ + if err != nil { + return written, err + } + } + return written, nil + } + for _, lp := range in { err := w.WriteByte(separator) written++ if err != nil { return written, err } - n, err := w.WriteString(lp.GetName()) + n, err := writeName(w, lp.GetName()) written += n if err != nil { return written, err @@ -451,7 +482,7 @@ func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) { if err != nil { return written, err } - n, err = writeOpenMetricsLabelPairs(w, e.Label, "", 0) + n, err = writeOpenMetricsNameAndLabelPairs(w, "", e.Label, "", 0) written += n if err != nil { return written, err diff --git a/vendor/github.com/prometheus/common/expfmt/text_create.go b/vendor/github.com/prometheus/common/expfmt/text_create.go index 5ba503b06..f9b8265a9 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_create.go +++ b/vendor/github.com/prometheus/common/expfmt/text_create.go @@ -17,7 +17,6 @@ import ( "bufio" "fmt" "io" - "io/ioutil" "math" "strconv" "strings" @@ -44,7 +43,7 @@ const ( var ( bufPool = sync.Pool{ New: func() interface{} { - return bufio.NewWriter(ioutil.Discard) + return bufio.NewWriter(io.Discard) }, } numBufPool = sync.Pool{ @@ -63,6 +62,18 @@ var ( // contains duplicate metrics or invalid metric or label names, the conversion // will result in invalid text format output. // +// If metric names conform to the legacy validation pattern, they will be placed +// outside the brackets in the traditional way, like `foo{}`. If the metric name +// fails the legacy validation check, it will be placed quoted inside the +// brackets: `{"foo"}`. As stated above, the input is assumed to be santized and +// no error will be thrown in this case. +// +// Similar to metric names, if label names conform to the legacy validation +// pattern, they will be unquoted as normal, like `foo{bar="baz"}`. If the label +// name fails the legacy validation check, it will be quoted: +// `foo{"bar"="baz"}`. As stated above, the input is assumed to be santized and +// no error will be thrown in this case. +// // This method fulfills the type 'prometheus.encoder'. func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) { // Fail-fast checks. @@ -99,7 +110,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e if err != nil { return } - n, err = w.WriteString(name) + n, err = writeName(w, name) written += n if err != nil { return @@ -125,7 +136,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e if err != nil { return } - n, err = w.WriteString(name) + n, err = writeName(w, name) written += n if err != nil { return @@ -281,21 +292,9 @@ func writeSample( additionalLabelName string, additionalLabelValue float64, value float64, ) (int, error) { - var written int - n, err := w.WriteString(name) - written += n - if err != nil { - return written, err - } - if suffix != "" { - n, err = w.WriteString(suffix) - written += n - if err != nil { - return written, err - } - } - n, err = writeLabelPairs( - w, metric.Label, additionalLabelName, additionalLabelValue, + written := 0 + n, err := writeNameAndLabelPairs( + w, name+suffix, metric.Label, additionalLabelName, additionalLabelValue, ) written += n if err != nil { @@ -331,32 +330,64 @@ func writeSample( return written, nil } -// writeLabelPairs converts a slice of LabelPair proto messages plus the -// explicitly given additional label pair into text formatted as required by the -// text format and writes it to 'w'. An empty slice in combination with an empty -// string 'additionalLabelName' results in nothing being written. Otherwise, the -// label pairs are written, escaped as required by the text format, and enclosed -// in '{...}'. The function returns the number of bytes written and any error -// encountered. -func writeLabelPairs( +// writeNameAndLabelPairs converts a slice of LabelPair proto messages plus the +// explicitly given metric name and additional label pair into text formatted as +// required by the text format and writes it to 'w'. An empty slice in +// combination with an empty string 'additionalLabelName' results in nothing +// being written. Otherwise, the label pairs are written, escaped as required by +// the text format, and enclosed in '{...}'. The function returns the number of +// bytes written and any error encountered. If the metric name is not +// legacy-valid, it will be put inside the brackets as well. Legacy-invalid +// label names will also be quoted. +func writeNameAndLabelPairs( w enhancedWriter, + name string, in []*dto.LabelPair, additionalLabelName string, additionalLabelValue float64, ) (int, error) { - if len(in) == 0 && additionalLabelName == "" { - return 0, nil - } var ( - written int - separator byte = '{' + written int + separator byte = '{' + metricInsideBraces = false ) + + if name != "" { + // If the name does not pass the legacy validity check, we must put the + // metric name inside the braces. + if !model.IsValidLegacyMetricName(model.LabelValue(name)) { + metricInsideBraces = true + err := w.WriteByte(separator) + written++ + if err != nil { + return written, err + } + separator = ',' + } + n, err := writeName(w, name) + written += n + if err != nil { + return written, err + } + } + + if len(in) == 0 && additionalLabelName == "" { + if metricInsideBraces { + err := w.WriteByte('}') + written++ + if err != nil { + return written, err + } + } + return written, nil + } + for _, lp := range in { err := w.WriteByte(separator) written++ if err != nil { return written, err } - n, err := w.WriteString(lp.GetName()) + n, err := writeName(w, lp.GetName()) written += n if err != nil { return written, err @@ -463,3 +494,27 @@ func writeInt(w enhancedWriter, i int64) (int, error) { numBufPool.Put(bp) return written, err } + +// writeName writes a string as-is if it complies with the legacy naming +// scheme, or escapes it in double quotes if not. +func writeName(w enhancedWriter, name string) (int, error) { + if model.IsValidLegacyMetricName(model.LabelValue(name)) { + return w.WriteString(name) + } + var written int + var err error + err = w.WriteByte('"') + written++ + if err != nil { + return written, err + } + var n int + n, err = writeEscapedString(w, name, true) + written += n + if err != nil { + return written, err + } + err = w.WriteByte('"') + written++ + return written, err +} diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse.go b/vendor/github.com/prometheus/common/expfmt/text_parse.go index 84be0643e..26490211a 100644 --- a/vendor/github.com/prometheus/common/expfmt/text_parse.go +++ b/vendor/github.com/prometheus/common/expfmt/text_parse.go @@ -16,6 +16,7 @@ package expfmt import ( "bufio" "bytes" + "errors" "fmt" "io" "math" @@ -24,7 +25,8 @@ import ( dto "github.com/prometheus/client_model/go" - "github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. + "google.golang.org/protobuf/proto" + "github.com/prometheus/common/model" ) @@ -112,7 +114,7 @@ func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricF // stream. Turn this error into something nicer and more // meaningful. (io.EOF is often used as a signal for the legitimate end // of an input stream.) - if p.err == io.EOF { + if p.err != nil && errors.Is(p.err, io.EOF) { p.parseError("unexpected end of input stream") } return p.metricFamiliesByName, p.err @@ -142,9 +144,13 @@ func (p *TextParser) reset(in io.Reader) { func (p *TextParser) startOfLine() stateFn { p.lineCount++ if p.skipBlankTab(); p.err != nil { - // End of input reached. This is the only case where - // that is not an error but a signal that we are done. - p.err = nil + // This is the only place that we expect to see io.EOF, + // which is not an error but the signal that we are done. + // Any other error that happens to align with the start of + // a line is still an error. + if errors.Is(p.err, io.EOF) { + p.err = nil + } return nil } switch p.currentByte { diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go index 26e92288c..a21b9d15d 100644 --- a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go +++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go @@ -11,18 +11,18 @@ 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 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. + 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 the Open Knowledge Foundation Ltd. nor the - names of its contributors may be used to endorse or promote - products derived from this software without specific prior written - permission. + Neither the name of the Open Knowledge Foundation Ltd. 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 @@ -35,8 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ package goautoneg diff --git a/vendor/github.com/prometheus/common/model/alert.go b/vendor/github.com/prometheus/common/model/alert.go index 35e739c7a..178fdbaf6 100644 --- a/vendor/github.com/prometheus/common/model/alert.go +++ b/vendor/github.com/prometheus/common/model/alert.go @@ -90,13 +90,13 @@ func (a *Alert) Validate() error { return fmt.Errorf("start time must be before end time") } if err := a.Labels.Validate(); err != nil { - return fmt.Errorf("invalid label set: %s", err) + return fmt.Errorf("invalid label set: %w", err) } if len(a.Labels) == 0 { return fmt.Errorf("at least one label pair required") } if err := a.Annotations.Validate(); err != nil { - return fmt.Errorf("invalid annotations: %s", err) + return fmt.Errorf("invalid annotations: %w", err) } return nil } diff --git a/vendor/github.com/prometheus/common/model/labels.go b/vendor/github.com/prometheus/common/model/labels.go index ef8956335..3317ce22f 100644 --- a/vendor/github.com/prometheus/common/model/labels.go +++ b/vendor/github.com/prometheus/common/model/labels.go @@ -97,17 +97,25 @@ var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") // therewith. type LabelName string -// IsValid is true iff the label name matches the pattern of LabelNameRE. This -// method, however, does not use LabelNameRE for the check but a much faster -// hardcoded implementation. +// IsValid returns true iff name matches the pattern of LabelNameRE for legacy +// names, and iff it's valid UTF-8 if NameValidationScheme is set to +// UTF8Validation. For the legacy matching, it does not use LabelNameRE for the +// check but a much faster hardcoded implementation. func (ln LabelName) IsValid() bool { if len(ln) == 0 { return false } - for i, b := range ln { - if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { - return false + switch NameValidationScheme { + case LegacyValidation: + for i, b := range ln { + if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { + return false + } } + case UTF8Validation: + return utf8.ValidString(string(ln)) + default: + panic(fmt.Sprintf("Invalid name validation scheme requested: %d", NameValidationScheme)) } return true } @@ -164,7 +172,7 @@ func (l LabelNames) String() string { // A LabelValue is an associated value for a LabelName. type LabelValue string -// IsValid returns true iff the string is a valid UTF8. +// IsValid returns true iff the string is a valid UTF-8. func (lv LabelValue) IsValid() bool { return utf8.ValidString(string(lv)) } diff --git a/vendor/github.com/prometheus/common/model/metadata.go b/vendor/github.com/prometheus/common/model/metadata.go new file mode 100644 index 000000000..447ab8ad6 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/metadata.go @@ -0,0 +1,28 @@ +// Copyright 2023 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 model + +// MetricType represents metric type values. +type MetricType string + +const ( + MetricTypeCounter = MetricType("counter") + MetricTypeGauge = MetricType("gauge") + MetricTypeHistogram = MetricType("histogram") + MetricTypeGaugeHistogram = MetricType("gaugehistogram") + MetricTypeSummary = MetricType("summary") + MetricTypeInfo = MetricType("info") + MetricTypeStateset = MetricType("stateset") + MetricTypeUnknown = MetricType("unknown") +) diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go index 00804b7fe..0bd29b3a3 100644 --- a/vendor/github.com/prometheus/common/model/metric.go +++ b/vendor/github.com/prometheus/common/model/metric.go @@ -18,15 +18,84 @@ import ( "regexp" "sort" "strings" + "unicode/utf8" + + dto "github.com/prometheus/client_model/go" + "google.golang.org/protobuf/proto" ) var ( - // MetricNameRE is a regular expression matching valid metric - // names. Note that the IsValidMetricName function performs the same - // check but faster than a match with this regular expression. - MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) + // NameValidationScheme determines the method of name validation to be used by + // all calls to IsValidMetricName() and LabelName IsValid(). Setting UTF-8 mode + // in isolation from other components that don't support UTF-8 may result in + // bugs or other undefined behavior. This value is intended to be set by + // UTF-8-aware binaries as part of their startup. To avoid need for locking, + // this value should be set once, ideally in an init(), before multiple + // goroutines are started. + NameValidationScheme = LegacyValidation + + // NameEscapingScheme defines the default way that names will be + // escaped when presented to systems that do not support UTF-8 names. If the + // Content-Type "escaping" term is specified, that will override this value. + NameEscapingScheme = ValueEncodingEscaping +) + +// ValidationScheme is a Go enum for determining how metric and label names will +// be validated by this library. +type ValidationScheme int + +const ( + // LegacyValidation is a setting that requirets that metric and label names + // conform to the original Prometheus character requirements described by + // MetricNameRE and LabelNameRE. + LegacyValidation ValidationScheme = iota + + // UTF8Validation only requires that metric and label names be valid UTF-8 + // strings. + UTF8Validation +) + +type EscapingScheme int + +const ( + // NoEscaping indicates that a name will not be escaped. Unescaped names that + // do not conform to the legacy validity check will use a new exposition + // format syntax that will be officially standardized in future versions. + NoEscaping EscapingScheme = iota + + // UnderscoreEscaping replaces all legacy-invalid characters with underscores. + UnderscoreEscaping + + // DotsEscaping is similar to UnderscoreEscaping, except that dots are + // converted to `_dot_` and pre-existing underscores are converted to `__`. + DotsEscaping + + // ValueEncodingEscaping prepends the name with `U__` and replaces all invalid + // characters with the unicode value, surrounded by underscores. Single + // underscores are replaced with double underscores. + ValueEncodingEscaping +) + +const ( + // EscapingKey is the key in an Accept or Content-Type header that defines how + // metric and label names that do not conform to the legacy character + // requirements should be escaped when being scraped by a legacy prometheus + // system. If a system does not explicitly pass an escaping parameter in the + // Accept header, the default NameEscapingScheme will be used. + EscapingKey = "escaping" + + // Possible values for Escaping Key: + AllowUTF8 = "allow-utf-8" // No escaping required. + EscapeUnderscores = "underscores" + EscapeDots = "dots" + EscapeValues = "values" ) +// MetricNameRE is a regular expression matching valid metric +// names. Note that the IsValidMetricName function performs the same +// check but faster than a match with this regular expression. +var MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) + // A Metric is similar to a LabelSet, but the key difference is that a Metric is // a singleton and refers to one and only one stream of samples. type Metric LabelSet @@ -86,17 +155,302 @@ func (m Metric) FastFingerprint() Fingerprint { return LabelSet(m).FastFingerprint() } -// IsValidMetricName returns true iff name matches the pattern of MetricNameRE. +// IsValidMetricName returns true iff name matches the pattern of MetricNameRE +// for legacy names, and iff it's valid UTF-8 if the UTF8Validation scheme is +// selected. +func IsValidMetricName(n LabelValue) bool { + switch NameValidationScheme { + case LegacyValidation: + return IsValidLegacyMetricName(n) + case UTF8Validation: + if len(n) == 0 { + return false + } + return utf8.ValidString(string(n)) + default: + panic(fmt.Sprintf("Invalid name validation scheme requested: %d", NameValidationScheme)) + } +} + +// IsValidLegacyMetricName is similar to IsValidMetricName but always uses the +// legacy validation scheme regardless of the value of NameValidationScheme. // This function, however, does not use MetricNameRE for the check but a much // faster hardcoded implementation. -func IsValidMetricName(n LabelValue) bool { +func IsValidLegacyMetricName(n LabelValue) bool { if len(n) == 0 { return false } for i, b := range n { - if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) { + if !isValidLegacyRune(b, i) { return false } } return true } + +// EscapeMetricFamily escapes the given metric names and labels with the given +// escaping scheme. Returns a new object that uses the same pointers to fields +// when possible and creates new escaped versions so as not to mutate the +// input. +func EscapeMetricFamily(v *dto.MetricFamily, scheme EscapingScheme) *dto.MetricFamily { + if v == nil { + return nil + } + + if scheme == NoEscaping { + return v + } + + out := &dto.MetricFamily{ + Help: v.Help, + Type: v.Type, + } + + // If the name is nil, copy as-is, don't try to escape. + if v.Name == nil || IsValidLegacyMetricName(LabelValue(v.GetName())) { + out.Name = v.Name + } else { + out.Name = proto.String(EscapeName(v.GetName(), scheme)) + } + for _, m := range v.Metric { + if !metricNeedsEscaping(m) { + out.Metric = append(out.Metric, m) + continue + } + + escaped := &dto.Metric{ + Gauge: m.Gauge, + Counter: m.Counter, + Summary: m.Summary, + Untyped: m.Untyped, + Histogram: m.Histogram, + TimestampMs: m.TimestampMs, + } + + for _, l := range m.Label { + if l.GetName() == MetricNameLabel { + if l.Value == nil || IsValidLegacyMetricName(LabelValue(l.GetValue())) { + escaped.Label = append(escaped.Label, l) + continue + } + escaped.Label = append(escaped.Label, &dto.LabelPair{ + Name: proto.String(MetricNameLabel), + Value: proto.String(EscapeName(l.GetValue(), scheme)), + }) + continue + } + if l.Name == nil || IsValidLegacyMetricName(LabelValue(l.GetName())) { + escaped.Label = append(escaped.Label, l) + continue + } + escaped.Label = append(escaped.Label, &dto.LabelPair{ + Name: proto.String(EscapeName(l.GetName(), scheme)), + Value: l.Value, + }) + } + out.Metric = append(out.Metric, escaped) + } + return out +} + +func metricNeedsEscaping(m *dto.Metric) bool { + for _, l := range m.Label { + if l.GetName() == MetricNameLabel && !IsValidLegacyMetricName(LabelValue(l.GetValue())) { + return true + } + if !IsValidLegacyMetricName(LabelValue(l.GetName())) { + return true + } + } + return false +} + +const ( + lowerhex = "0123456789abcdef" +) + +// EscapeName escapes the incoming name according to the provided escaping +// scheme. Depending on the rules of escaping, this may cause no change in the +// string that is returned. (Especially NoEscaping, which by definition is a +// noop). This function does not do any validation of the name. +func EscapeName(name string, scheme EscapingScheme) string { + if len(name) == 0 { + return name + } + var escaped strings.Builder + switch scheme { + case NoEscaping: + return name + case UnderscoreEscaping: + if IsValidLegacyMetricName(LabelValue(name)) { + return name + } + for i, b := range name { + if isValidLegacyRune(b, i) { + escaped.WriteRune(b) + } else { + escaped.WriteRune('_') + } + } + return escaped.String() + case DotsEscaping: + // Do not early return for legacy valid names, we still escape underscores. + for i, b := range name { + if b == '_' { + escaped.WriteString("__") + } else if b == '.' { + escaped.WriteString("_dot_") + } else if isValidLegacyRune(b, i) { + escaped.WriteRune(b) + } else { + escaped.WriteRune('_') + } + } + return escaped.String() + case ValueEncodingEscaping: + if IsValidLegacyMetricName(LabelValue(name)) { + return name + } + escaped.WriteString("U__") + for i, b := range name { + if isValidLegacyRune(b, i) { + escaped.WriteRune(b) + } else if !utf8.ValidRune(b) { + escaped.WriteString("_FFFD_") + } else if b < 0x100 { + escaped.WriteRune('_') + for s := 4; s >= 0; s -= 4 { + escaped.WriteByte(lowerhex[b>>uint(s)&0xF]) + } + escaped.WriteRune('_') + } else if b < 0x10000 { + escaped.WriteRune('_') + for s := 12; s >= 0; s -= 4 { + escaped.WriteByte(lowerhex[b>>uint(s)&0xF]) + } + escaped.WriteRune('_') + } + } + return escaped.String() + default: + panic(fmt.Sprintf("invalid escaping scheme %d", scheme)) + } +} + +// lower function taken from strconv.atoi +func lower(c byte) byte { + return c | ('x' - 'X') +} + +// UnescapeName unescapes the incoming name according to the provided escaping +// scheme if possible. Some schemes are partially or totally non-roundtripable. +// If any error is enountered, returns the original input. +func UnescapeName(name string, scheme EscapingScheme) string { + if len(name) == 0 { + return name + } + switch scheme { + case NoEscaping: + return name + case UnderscoreEscaping: + // It is not possible to unescape from underscore replacement. + return name + case DotsEscaping: + name = strings.ReplaceAll(name, "_dot_", ".") + name = strings.ReplaceAll(name, "__", "_") + return name + case ValueEncodingEscaping: + escapedName, found := strings.CutPrefix(name, "U__") + if !found { + return name + } + + var unescaped strings.Builder + TOP: + for i := 0; i < len(escapedName); i++ { + // All non-underscores are treated normally. + if escapedName[i] != '_' { + unescaped.WriteByte(escapedName[i]) + continue + } + i++ + if i >= len(escapedName) { + return name + } + // A double underscore is a single underscore. + if escapedName[i] == '_' { + unescaped.WriteByte('_') + continue + } + // We think we are in a UTF-8 code, process it. + var utf8Val uint + for j := 0; i < len(escapedName); j++ { + // This is too many characters for a utf8 value. + if j > 4 { + return name + } + // Found a closing underscore, convert to a rune, check validity, and append. + if escapedName[i] == '_' { + utf8Rune := rune(utf8Val) + if !utf8.ValidRune(utf8Rune) { + return name + } + unescaped.WriteRune(utf8Rune) + continue TOP + } + r := lower(escapedName[i]) + utf8Val *= 16 + if r >= '0' && r <= '9' { + utf8Val += uint(r) - '0' + } else if r >= 'a' && r <= 'f' { + utf8Val += uint(r) - 'a' + 10 + } else { + return name + } + i++ + } + // Didn't find closing underscore, invalid. + return name + } + return unescaped.String() + default: + panic(fmt.Sprintf("invalid escaping scheme %d", scheme)) + } +} + +func isValidLegacyRune(b rune, i int) bool { + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0) +} + +func (e EscapingScheme) String() string { + switch e { + case NoEscaping: + return AllowUTF8 + case UnderscoreEscaping: + return EscapeUnderscores + case DotsEscaping: + return EscapeDots + case ValueEncodingEscaping: + return EscapeValues + default: + panic(fmt.Sprintf("unknown format scheme %d", e)) + } +} + +func ToEscapingScheme(s string) (EscapingScheme, error) { + if s == "" { + return NoEscaping, fmt.Errorf("got empty string instead of escaping scheme") + } + switch s { + case AllowUTF8: + return NoEscaping, nil + case EscapeUnderscores: + return UnderscoreEscaping, nil + case EscapeDots: + return DotsEscaping, nil + case EscapeValues: + return ValueEncodingEscaping, nil + default: + return NoEscaping, fmt.Errorf("unknown format scheme " + s) + } +} diff --git a/vendor/github.com/prometheus/common/model/signature.go b/vendor/github.com/prometheus/common/model/signature.go index 8762b13c6..dc8a0026c 100644 --- a/vendor/github.com/prometheus/common/model/signature.go +++ b/vendor/github.com/prometheus/common/model/signature.go @@ -22,10 +22,8 @@ import ( // when calculating their combined hash value (aka signature aka fingerprint). const SeparatorByte byte = 255 -var ( - // cache the signature of an empty label set. - emptyLabelSignature = hashNew() -) +// cache the signature of an empty label set. +var emptyLabelSignature = hashNew() // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a // given label set. (Collisions are possible but unlikely if the number of label diff --git a/vendor/github.com/prometheus/common/model/silence.go b/vendor/github.com/prometheus/common/model/silence.go index bb99889d2..910b0b71f 100644 --- a/vendor/github.com/prometheus/common/model/silence.go +++ b/vendor/github.com/prometheus/common/model/silence.go @@ -81,7 +81,7 @@ func (s *Silence) Validate() error { } for _, m := range s.Matchers { if err := m.Validate(); err != nil { - return fmt.Errorf("invalid matcher: %s", err) + return fmt.Errorf("invalid matcher: %w", err) } } if s.StartsAt.IsZero() { diff --git a/vendor/github.com/prometheus/common/model/time.go b/vendor/github.com/prometheus/common/model/time.go index c909b8aa8..5727452c1 100644 --- a/vendor/github.com/prometheus/common/model/time.go +++ b/vendor/github.com/prometheus/common/model/time.go @@ -18,7 +18,6 @@ import ( "errors" "fmt" "math" - "regexp" "strconv" "strings" "time" @@ -183,54 +182,78 @@ func (d *Duration) Type() string { return "duration" } -var durationRE = regexp.MustCompile("^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$") +func isdigit(c byte) bool { return c >= '0' && c <= '9' } + +// Units are required to go in order from biggest to smallest. +// This guards against confusion from "1m1d" being 1 minute + 1 day, not 1 month + 1 day. +var unitMap = map[string]struct { + pos int + mult uint64 +}{ + "ms": {7, uint64(time.Millisecond)}, + "s": {6, uint64(time.Second)}, + "m": {5, uint64(time.Minute)}, + "h": {4, uint64(time.Hour)}, + "d": {3, uint64(24 * time.Hour)}, + "w": {2, uint64(7 * 24 * time.Hour)}, + "y": {1, uint64(365 * 24 * time.Hour)}, +} // ParseDuration parses a string into a time.Duration, assuming that a year // always has 365d, a week always has 7d, and a day always has 24h. -func ParseDuration(durationStr string) (Duration, error) { - switch durationStr { +func ParseDuration(s string) (Duration, error) { + switch s { case "0": // Allow 0 without a unit. return 0, nil case "": return 0, errors.New("empty duration string") } - matches := durationRE.FindStringSubmatch(durationStr) - if matches == nil { - return 0, fmt.Errorf("not a valid duration string: %q", durationStr) - } - var dur time.Duration - // Parse the match at pos `pos` in the regex and use `mult` to turn that - // into ms, then add that value to the total parsed duration. - var overflowErr error - m := func(pos int, mult time.Duration) { - if matches[pos] == "" { - return + orig := s + var dur uint64 + lastUnitPos := 0 + + for s != "" { + if !isdigit(s[0]) { + return 0, fmt.Errorf("not a valid duration string: %q", orig) + } + // Consume [0-9]* + i := 0 + for ; i < len(s) && isdigit(s[i]); i++ { + } + v, err := strconv.ParseUint(s[:i], 10, 0) + if err != nil { + return 0, fmt.Errorf("not a valid duration string: %q", orig) } - n, _ := strconv.Atoi(matches[pos]) + s = s[i:] + // Consume unit. + for i = 0; i < len(s) && !isdigit(s[i]); i++ { + } + if i == 0 { + return 0, fmt.Errorf("not a valid duration string: %q", orig) + } + u := s[:i] + s = s[i:] + unit, ok := unitMap[u] + if !ok { + return 0, fmt.Errorf("unknown unit %q in duration %q", u, orig) + } + if unit.pos <= lastUnitPos { // Units must go in order from biggest to smallest. + return 0, fmt.Errorf("not a valid duration string: %q", orig) + } + lastUnitPos = unit.pos // Check if the provided duration overflows time.Duration (> ~ 290years). - if n > int((1<<63-1)/mult/time.Millisecond) { - overflowErr = errors.New("duration out of range") + if v > 1<<63/unit.mult { + return 0, errors.New("duration out of range") } - d := time.Duration(n) * time.Millisecond - dur += d * mult - - if dur < 0 { - overflowErr = errors.New("duration out of range") + dur += v * unit.mult + if dur > 1<<63-1 { + return 0, errors.New("duration out of range") } } - - m(2, 1000*60*60*24*365) // y - m(4, 1000*60*60*24*7) // w - m(6, 1000*60*60*24) // d - m(8, 1000*60*60) // h - m(10, 1000*60) // m - m(12, 1000) // s - m(14, 1) // ms - - return Duration(dur), overflowErr + return Duration(dur), nil } func (d Duration) String() string { diff --git a/vendor/github.com/prometheus/common/model/value.go b/vendor/github.com/prometheus/common/model/value.go index c9d8fb1a2..8050637d8 100644 --- a/vendor/github.com/prometheus/common/model/value.go +++ b/vendor/github.com/prometheus/common/model/value.go @@ -16,104 +16,26 @@ package model import ( "encoding/json" "fmt" - "math" "sort" "strconv" "strings" ) -var ( - // ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a - // non-existing sample pair. It is a SamplePair with timestamp Earliest and - // value 0.0. Note that the natural zero value of SamplePair has a timestamp - // of 0, which is possible to appear in a real SamplePair and thus not - // suitable to signal a non-existing SamplePair. - ZeroSamplePair = SamplePair{Timestamp: Earliest} - - // ZeroSample is the pseudo zero-value of Sample used to signal a - // non-existing sample. It is a Sample with timestamp Earliest, value 0.0, - // and metric nil. Note that the natural zero value of Sample has a timestamp - // of 0, which is possible to appear in a real Sample and thus not suitable - // to signal a non-existing Sample. - ZeroSample = Sample{Timestamp: Earliest} -) - -// A SampleValue is a representation of a value for a given sample at a given -// time. -type SampleValue float64 - -// MarshalJSON implements json.Marshaler. -func (v SampleValue) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -// UnmarshalJSON implements json.Unmarshaler. -func (v *SampleValue) UnmarshalJSON(b []byte) error { - if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { - return fmt.Errorf("sample value must be a quoted string") - } - f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64) - if err != nil { - return err - } - *v = SampleValue(f) - return nil -} - -// Equal returns true if the value of v and o is equal or if both are NaN. Note -// that v==o is false if both are NaN. If you want the conventional float -// behavior, use == to compare two SampleValues. -func (v SampleValue) Equal(o SampleValue) bool { - if v == o { - return true - } - return math.IsNaN(float64(v)) && math.IsNaN(float64(o)) -} - -func (v SampleValue) String() string { - return strconv.FormatFloat(float64(v), 'f', -1, 64) -} - -// SamplePair pairs a SampleValue with a Timestamp. -type SamplePair struct { - Timestamp Time - Value SampleValue -} - -// MarshalJSON implements json.Marshaler. -func (s SamplePair) MarshalJSON() ([]byte, error) { - t, err := json.Marshal(s.Timestamp) - if err != nil { - return nil, err - } - v, err := json.Marshal(s.Value) - if err != nil { - return nil, err - } - return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil -} - -// UnmarshalJSON implements json.Unmarshaler. -func (s *SamplePair) UnmarshalJSON(b []byte) error { - v := [...]json.Unmarshaler{&s.Timestamp, &s.Value} - return json.Unmarshal(b, &v) -} - -// Equal returns true if this SamplePair and o have equal Values and equal -// Timestamps. The semantics of Value equality is defined by SampleValue.Equal. -func (s *SamplePair) Equal(o *SamplePair) bool { - return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp)) -} - -func (s SamplePair) String() string { - return fmt.Sprintf("%s @[%s]", s.Value, s.Timestamp) -} +// ZeroSample is the pseudo zero-value of Sample used to signal a +// non-existing sample. It is a Sample with timestamp Earliest, value 0.0, +// and metric nil. Note that the natural zero value of Sample has a timestamp +// of 0, which is possible to appear in a real Sample and thus not suitable +// to signal a non-existing Sample. +var ZeroSample = Sample{Timestamp: Earliest} -// Sample is a sample pair associated with a metric. +// Sample is a sample pair associated with a metric. A single sample must either +// define Value or Histogram but not both. Histogram == nil implies the Value +// field is used, otherwise it should be ignored. type Sample struct { - Metric Metric `json:"metric"` - Value SampleValue `json:"value"` - Timestamp Time `json:"timestamp"` + Metric Metric `json:"metric"` + Value SampleValue `json:"value"` + Timestamp Time `json:"timestamp"` + Histogram *SampleHistogram `json:"histogram"` } // Equal compares first the metrics, then the timestamp, then the value. The @@ -129,11 +51,19 @@ func (s *Sample) Equal(o *Sample) bool { if !s.Timestamp.Equal(o.Timestamp) { return false } - + if s.Histogram != nil { + return s.Histogram.Equal(o.Histogram) + } return s.Value.Equal(o.Value) } func (s Sample) String() string { + if s.Histogram != nil { + return fmt.Sprintf("%s => %s", s.Metric, SampleHistogramPair{ + Timestamp: s.Timestamp, + Histogram: s.Histogram, + }) + } return fmt.Sprintf("%s => %s", s.Metric, SamplePair{ Timestamp: s.Timestamp, Value: s.Value, @@ -142,6 +72,19 @@ func (s Sample) String() string { // MarshalJSON implements json.Marshaler. func (s Sample) MarshalJSON() ([]byte, error) { + if s.Histogram != nil { + v := struct { + Metric Metric `json:"metric"` + Histogram SampleHistogramPair `json:"histogram"` + }{ + Metric: s.Metric, + Histogram: SampleHistogramPair{ + Timestamp: s.Timestamp, + Histogram: s.Histogram, + }, + } + return json.Marshal(&v) + } v := struct { Metric Metric `json:"metric"` Value SamplePair `json:"value"` @@ -152,21 +95,25 @@ func (s Sample) MarshalJSON() ([]byte, error) { Value: s.Value, }, } - return json.Marshal(&v) } // UnmarshalJSON implements json.Unmarshaler. func (s *Sample) UnmarshalJSON(b []byte) error { v := struct { - Metric Metric `json:"metric"` - Value SamplePair `json:"value"` + Metric Metric `json:"metric"` + Value SamplePair `json:"value"` + Histogram SampleHistogramPair `json:"histogram"` }{ Metric: s.Metric, Value: SamplePair{ Timestamp: s.Timestamp, Value: s.Value, }, + Histogram: SampleHistogramPair{ + Timestamp: s.Timestamp, + Histogram: s.Histogram, + }, } if err := json.Unmarshal(b, &v); err != nil { @@ -174,8 +121,13 @@ func (s *Sample) UnmarshalJSON(b []byte) error { } s.Metric = v.Metric - s.Timestamp = v.Value.Timestamp - s.Value = v.Value.Value + if v.Histogram.Histogram != nil { + s.Timestamp = v.Histogram.Timestamp + s.Histogram = v.Histogram.Histogram + } else { + s.Timestamp = v.Value.Timestamp + s.Value = v.Value.Value + } return nil } @@ -221,80 +173,76 @@ func (s Samples) Equal(o Samples) bool { // SampleStream is a stream of Values belonging to an attached COWMetric. type SampleStream struct { - Metric Metric `json:"metric"` - Values []SamplePair `json:"values"` + Metric Metric `json:"metric"` + Values []SamplePair `json:"values"` + Histograms []SampleHistogramPair `json:"histograms"` } func (ss SampleStream) String() string { - vals := make([]string, len(ss.Values)) + valuesLength := len(ss.Values) + vals := make([]string, valuesLength+len(ss.Histograms)) for i, v := range ss.Values { vals[i] = v.String() } + for i, v := range ss.Histograms { + vals[i+valuesLength] = v.String() + } return fmt.Sprintf("%s =>\n%s", ss.Metric, strings.Join(vals, "\n")) } -// Value is a generic interface for values resulting from a query evaluation. -type Value interface { - Type() ValueType - String() string +func (ss SampleStream) MarshalJSON() ([]byte, error) { + if len(ss.Histograms) > 0 && len(ss.Values) > 0 { + v := struct { + Metric Metric `json:"metric"` + Values []SamplePair `json:"values"` + Histograms []SampleHistogramPair `json:"histograms"` + }{ + Metric: ss.Metric, + Values: ss.Values, + Histograms: ss.Histograms, + } + return json.Marshal(&v) + } else if len(ss.Histograms) > 0 { + v := struct { + Metric Metric `json:"metric"` + Histograms []SampleHistogramPair `json:"histograms"` + }{ + Metric: ss.Metric, + Histograms: ss.Histograms, + } + return json.Marshal(&v) + } else { + v := struct { + Metric Metric `json:"metric"` + Values []SamplePair `json:"values"` + }{ + Metric: ss.Metric, + Values: ss.Values, + } + return json.Marshal(&v) + } } -func (Matrix) Type() ValueType { return ValMatrix } -func (Vector) Type() ValueType { return ValVector } -func (*Scalar) Type() ValueType { return ValScalar } -func (*String) Type() ValueType { return ValString } - -type ValueType int - -const ( - ValNone ValueType = iota - ValScalar - ValVector - ValMatrix - ValString -) - -// MarshalJSON implements json.Marshaler. -func (et ValueType) MarshalJSON() ([]byte, error) { - return json.Marshal(et.String()) -} +func (ss *SampleStream) UnmarshalJSON(b []byte) error { + v := struct { + Metric Metric `json:"metric"` + Values []SamplePair `json:"values"` + Histograms []SampleHistogramPair `json:"histograms"` + }{ + Metric: ss.Metric, + Values: ss.Values, + Histograms: ss.Histograms, + } -func (et *ValueType) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { + if err := json.Unmarshal(b, &v); err != nil { return err } - switch s { - case "": - *et = ValNone - case "scalar": - *et = ValScalar - case "vector": - *et = ValVector - case "matrix": - *et = ValMatrix - case "string": - *et = ValString - default: - return fmt.Errorf("unknown value type %q", s) - } - return nil -} -func (e ValueType) String() string { - switch e { - case ValNone: - return "" - case ValScalar: - return "scalar" - case ValVector: - return "vector" - case ValMatrix: - return "matrix" - case ValString: - return "string" - } - panic("ValueType.String: unhandled value type") + ss.Metric = v.Metric + ss.Values = v.Values + ss.Histograms = v.Histograms + + return nil } // Scalar is a scalar value evaluated at the set timestamp. @@ -324,7 +272,7 @@ func (s *Scalar) UnmarshalJSON(b []byte) error { value, err := strconv.ParseFloat(f, 64) if err != nil { - return fmt.Errorf("error parsing sample value: %s", err) + return fmt.Errorf("error parsing sample value: %w", err) } s.Value = SampleValue(value) return nil diff --git a/vendor/github.com/prometheus/common/model/value_float.go b/vendor/github.com/prometheus/common/model/value_float.go new file mode 100644 index 000000000..ae35cc2ab --- /dev/null +++ b/vendor/github.com/prometheus/common/model/value_float.go @@ -0,0 +1,98 @@ +// Copyright 2013 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 model + +import ( + "encoding/json" + "fmt" + "math" + "strconv" +) + +// ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a +// non-existing sample pair. It is a SamplePair with timestamp Earliest and +// value 0.0. Note that the natural zero value of SamplePair has a timestamp +// of 0, which is possible to appear in a real SamplePair and thus not +// suitable to signal a non-existing SamplePair. +var ZeroSamplePair = SamplePair{Timestamp: Earliest} + +// A SampleValue is a representation of a value for a given sample at a given +// time. +type SampleValue float64 + +// MarshalJSON implements json.Marshaler. +func (v SampleValue) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (v *SampleValue) UnmarshalJSON(b []byte) error { + if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { + return fmt.Errorf("sample value must be a quoted string") + } + f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64) + if err != nil { + return err + } + *v = SampleValue(f) + return nil +} + +// Equal returns true if the value of v and o is equal or if both are NaN. Note +// that v==o is false if both are NaN. If you want the conventional float +// behavior, use == to compare two SampleValues. +func (v SampleValue) Equal(o SampleValue) bool { + if v == o { + return true + } + return math.IsNaN(float64(v)) && math.IsNaN(float64(o)) +} + +func (v SampleValue) String() string { + return strconv.FormatFloat(float64(v), 'f', -1, 64) +} + +// SamplePair pairs a SampleValue with a Timestamp. +type SamplePair struct { + Timestamp Time + Value SampleValue +} + +func (s SamplePair) MarshalJSON() ([]byte, error) { + t, err := json.Marshal(s.Timestamp) + if err != nil { + return nil, err + } + v, err := json.Marshal(s.Value) + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (s *SamplePair) UnmarshalJSON(b []byte) error { + v := [...]json.Unmarshaler{&s.Timestamp, &s.Value} + return json.Unmarshal(b, &v) +} + +// Equal returns true if this SamplePair and o have equal Values and equal +// Timestamps. The semantics of Value equality is defined by SampleValue.Equal. +func (s *SamplePair) Equal(o *SamplePair) bool { + return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp)) +} + +func (s SamplePair) String() string { + return fmt.Sprintf("%s @[%s]", s.Value, s.Timestamp) +} diff --git a/vendor/github.com/prometheus/common/model/value_histogram.go b/vendor/github.com/prometheus/common/model/value_histogram.go new file mode 100644 index 000000000..54bb038cf --- /dev/null +++ b/vendor/github.com/prometheus/common/model/value_histogram.go @@ -0,0 +1,178 @@ +// Copyright 2013 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 model + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" +) + +type FloatString float64 + +func (v FloatString) String() string { + return strconv.FormatFloat(float64(v), 'f', -1, 64) +} + +func (v FloatString) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} + +func (v *FloatString) UnmarshalJSON(b []byte) error { + if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { + return fmt.Errorf("float value must be a quoted string") + } + f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64) + if err != nil { + return err + } + *v = FloatString(f) + return nil +} + +type HistogramBucket struct { + Boundaries int32 + Lower FloatString + Upper FloatString + Count FloatString +} + +func (s HistogramBucket) MarshalJSON() ([]byte, error) { + b, err := json.Marshal(s.Boundaries) + if err != nil { + return nil, err + } + l, err := json.Marshal(s.Lower) + if err != nil { + return nil, err + } + u, err := json.Marshal(s.Upper) + if err != nil { + return nil, err + } + c, err := json.Marshal(s.Count) + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf("[%s,%s,%s,%s]", b, l, u, c)), nil +} + +func (s *HistogramBucket) UnmarshalJSON(buf []byte) error { + tmp := []interface{}{&s.Boundaries, &s.Lower, &s.Upper, &s.Count} + wantLen := len(tmp) + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if gotLen := len(tmp); gotLen != wantLen { + return fmt.Errorf("wrong number of fields: %d != %d", gotLen, wantLen) + } + return nil +} + +func (s *HistogramBucket) Equal(o *HistogramBucket) bool { + return s == o || (s.Boundaries == o.Boundaries && s.Lower == o.Lower && s.Upper == o.Upper && s.Count == o.Count) +} + +func (b HistogramBucket) String() string { + var sb strings.Builder + lowerInclusive := b.Boundaries == 1 || b.Boundaries == 3 + upperInclusive := b.Boundaries == 0 || b.Boundaries == 3 + if lowerInclusive { + sb.WriteRune('[') + } else { + sb.WriteRune('(') + } + fmt.Fprintf(&sb, "%g,%g", b.Lower, b.Upper) + if upperInclusive { + sb.WriteRune(']') + } else { + sb.WriteRune(')') + } + fmt.Fprintf(&sb, ":%v", b.Count) + return sb.String() +} + +type HistogramBuckets []*HistogramBucket + +func (s HistogramBuckets) Equal(o HistogramBuckets) bool { + if len(s) != len(o) { + return false + } + + for i, bucket := range s { + if !bucket.Equal(o[i]) { + return false + } + } + return true +} + +type SampleHistogram struct { + Count FloatString `json:"count"` + Sum FloatString `json:"sum"` + Buckets HistogramBuckets `json:"buckets"` +} + +func (s SampleHistogram) String() string { + return fmt.Sprintf("Count: %f, Sum: %f, Buckets: %v", s.Count, s.Sum, s.Buckets) +} + +func (s *SampleHistogram) Equal(o *SampleHistogram) bool { + return s == o || (s.Count == o.Count && s.Sum == o.Sum && s.Buckets.Equal(o.Buckets)) +} + +type SampleHistogramPair struct { + Timestamp Time + // Histogram should never be nil, it's only stored as pointer for efficiency. + Histogram *SampleHistogram +} + +func (s SampleHistogramPair) MarshalJSON() ([]byte, error) { + if s.Histogram == nil { + return nil, fmt.Errorf("histogram is nil") + } + t, err := json.Marshal(s.Timestamp) + if err != nil { + return nil, err + } + v, err := json.Marshal(s.Histogram) + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil +} + +func (s *SampleHistogramPair) UnmarshalJSON(buf []byte) error { + tmp := []interface{}{&s.Timestamp, &s.Histogram} + wantLen := len(tmp) + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if gotLen := len(tmp); gotLen != wantLen { + return fmt.Errorf("wrong number of fields: %d != %d", gotLen, wantLen) + } + if s.Histogram == nil { + return fmt.Errorf("histogram is null") + } + return nil +} + +func (s SampleHistogramPair) String() string { + return fmt.Sprintf("%s @[%s]", s.Histogram, s.Timestamp) +} + +func (s *SampleHistogramPair) Equal(o *SampleHistogramPair) bool { + return s == o || (s.Histogram.Equal(o.Histogram) && s.Timestamp.Equal(o.Timestamp)) +} diff --git a/vendor/github.com/prometheus/common/model/value_type.go b/vendor/github.com/prometheus/common/model/value_type.go new file mode 100644 index 000000000..726c50ee6 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/value_type.go @@ -0,0 +1,83 @@ +// Copyright 2013 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 model + +import ( + "encoding/json" + "fmt" +) + +// Value is a generic interface for values resulting from a query evaluation. +type Value interface { + Type() ValueType + String() string +} + +func (Matrix) Type() ValueType { return ValMatrix } +func (Vector) Type() ValueType { return ValVector } +func (*Scalar) Type() ValueType { return ValScalar } +func (*String) Type() ValueType { return ValString } + +type ValueType int + +const ( + ValNone ValueType = iota + ValScalar + ValVector + ValMatrix + ValString +) + +// MarshalJSON implements json.Marshaler. +func (et ValueType) MarshalJSON() ([]byte, error) { + return json.Marshal(et.String()) +} + +func (et *ValueType) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + switch s { + case "": + *et = ValNone + case "scalar": + *et = ValScalar + case "vector": + *et = ValVector + case "matrix": + *et = ValMatrix + case "string": + *et = ValString + default: + return fmt.Errorf("unknown value type %q", s) + } + return nil +} + +func (e ValueType) String() string { + switch e { + case ValNone: + return "" + case ValScalar: + return "scalar" + case ValVector: + return "vector" + case ValMatrix: + return "matrix" + case ValString: + return "string" + } + panic("ValueType.String: unhandled value type") +} diff --git a/vendor/github.com/prometheus/procfs/.golangci.yml b/vendor/github.com/prometheus/procfs/.golangci.yml index a197699a1..c24864a92 100644 --- a/vendor/github.com/prometheus/procfs/.golangci.yml +++ b/vendor/github.com/prometheus/procfs/.golangci.yml @@ -2,6 +2,7 @@ linters: enable: - godot + - misspell - revive linter-settings: @@ -10,3 +11,5 @@ linter-settings: exclude: # Ignore "See: URL" - 'See:' + misspell: + locale: US diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common index 6c8e3e219..062a28185 100644 --- a/vendor/github.com/prometheus/procfs/Makefile.common +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -49,25 +49,28 @@ endif GOTEST := $(GO) test GOTEST_DIR := ifneq ($(CIRCLE_JOB),) -ifneq ($(shell which gotestsum),) +ifneq ($(shell command -v gotestsum > /dev/null),) GOTEST_DIR := test-results GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml -- endif endif -PROMU_VERSION ?= 0.13.0 +PROMU_VERSION ?= 0.15.0 PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz +SKIP_GOLANGCI_LINT := GOLANGCI_LINT := GOLANGCI_LINT_OPTS ?= -GOLANGCI_LINT_VERSION ?= v1.45.2 +GOLANGCI_LINT_VERSION ?= v1.54.2 # golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # windows isn't included here because of the path separator being different. ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) # If we're in CI and there is an Actions file, that means the linter # is being run in Actions, so we don't need to run it here. - ifeq (,$(CIRCLE_JOB)) + ifneq (,$(SKIP_GOLANGCI_LINT)) + GOLANGCI_LINT := + else ifeq (,$(CIRCLE_JOB)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint else ifeq (,$(wildcard .github/workflows/golangci-lint.yml)) GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint @@ -88,6 +91,8 @@ BUILD_DOCKER_ARCHS = $(addprefix common-docker-,$(DOCKER_ARCHS)) PUBLISH_DOCKER_ARCHS = $(addprefix common-docker-publish-,$(DOCKER_ARCHS)) TAG_DOCKER_ARCHS = $(addprefix common-docker-tag-latest-,$(DOCKER_ARCHS)) +SANITIZED_DOCKER_IMAGE_TAG := $(subst +,-,$(DOCKER_IMAGE_TAG)) + ifeq ($(GOHOSTARCH),amd64) ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux freebsd darwin windows)) # Only supported on amd64 @@ -173,7 +178,7 @@ endif .PHONY: common-yamllint common-yamllint: @echo ">> running yamllint on all YAML files in the repository" -ifeq (, $(shell which yamllint)) +ifeq (, $(shell command -v yamllint > /dev/null)) @echo "yamllint not installed so skipping" else yamllint . @@ -202,7 +207,7 @@ common-tarball: promu .PHONY: common-docker $(BUILD_DOCKER_ARCHS) common-docker: $(BUILD_DOCKER_ARCHS) $(BUILD_DOCKER_ARCHS): common-docker-%: - docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" \ + docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" \ -f $(DOCKERFILE_PATH) \ --build-arg ARCH="$*" \ --build-arg OS="linux" \ @@ -211,19 +216,19 @@ $(BUILD_DOCKER_ARCHS): common-docker-%: .PHONY: common-docker-publish $(PUBLISH_DOCKER_ARCHS) common-docker-publish: $(PUBLISH_DOCKER_ARCHS) $(PUBLISH_DOCKER_ARCHS): common-docker-publish-%: - docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" + docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" DOCKER_MAJOR_VERSION_TAG = $(firstword $(subst ., ,$(shell cat VERSION))) .PHONY: common-docker-tag-latest $(TAG_DOCKER_ARCHS) common-docker-tag-latest: $(TAG_DOCKER_ARCHS) $(TAG_DOCKER_ARCHS): common-docker-tag-latest-%: - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" - docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:latest" + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:$(SANITIZED_DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$*:v$(DOCKER_MAJOR_VERSION_TAG)" .PHONY: common-docker-manifest common-docker-manifest: - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(DOCKER_IMAGE_TAG)) - DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create -a "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" $(foreach ARCH,$(DOCKER_ARCHS),$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)-linux-$(ARCH):$(SANITIZED_DOCKER_IMAGE_TAG)) + DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(SANITIZED_DOCKER_IMAGE_TAG)" .PHONY: promu promu: $(PROMU) diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md index 43c37735a..1224816c2 100644 --- a/vendor/github.com/prometheus/procfs/README.md +++ b/vendor/github.com/prometheus/procfs/README.md @@ -51,11 +51,11 @@ ensure the `fixtures` directory is up to date by removing the existing directory extracting the ttar file using `make fixtures/.unpacked` or just `make test`. ```bash -rm -rf fixtures +rm -rf testdata/fixtures make test ``` Next, make the required changes to the extracted files in the `fixtures` directory. When the changes are complete, run `make update_fixtures` to create a new `fixtures.ttar` file based on the updated `fixtures` directory. And finally, verify the changes using -`git diff fixtures.ttar`. +`git diff testdata/fixtures.ttar`. diff --git a/vendor/github.com/prometheus/procfs/arp.go b/vendor/github.com/prometheus/procfs/arp.go index 68f36e888..28783e2dd 100644 --- a/vendor/github.com/prometheus/procfs/arp.go +++ b/vendor/github.com/prometheus/procfs/arp.go @@ -55,7 +55,7 @@ type ARPEntry struct { func (fs FS) GatherARPEntries() ([]ARPEntry, error) { data, err := os.ReadFile(fs.proc.Path("net/arp")) if err != nil { - return nil, fmt.Errorf("error reading arp %q: %w", fs.proc.Path("net/arp"), err) + return nil, fmt.Errorf("%s: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err) } return parseARPEntries(data) @@ -78,11 +78,11 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) { } else if width == expectedDataWidth { entry, err := parseARPEntry(columns) if err != nil { - return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %w", err) + return []ARPEntry{}, fmt.Errorf("%s: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err) } entries = append(entries, entry) } else { - return []ARPEntry{}, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedDataWidth) + return []ARPEntry{}, fmt.Errorf("%s: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err) } } diff --git a/vendor/github.com/prometheus/procfs/buddyinfo.go b/vendor/github.com/prometheus/procfs/buddyinfo.go index f5b7939b2..4a173636c 100644 --- a/vendor/github.com/prometheus/procfs/buddyinfo.go +++ b/vendor/github.com/prometheus/procfs/buddyinfo.go @@ -55,7 +55,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { parts := strings.Fields(line) if len(parts) < 4 { - return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo") + return nil, fmt.Errorf("%w: Invalid number of fields, found: %v", ErrFileParse, parts) } node := strings.TrimRight(parts[1], ",") @@ -66,7 +66,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { bucketCount = arraySize } else { if bucketCount != arraySize { - return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize) + return nil, fmt.Errorf("%w: mismatch in number of buddyinfo buckets, previous count %d, new count %d", ErrFileParse, bucketCount, arraySize) } } @@ -74,7 +74,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { for i := 0; i < arraySize; i++ { sizes[i], err = strconv.ParseFloat(parts[i+4], 64) if err != nil { - return nil, fmt.Errorf("invalid value in buddyinfo: %w", err) + return nil, fmt.Errorf("%s: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err) } } diff --git a/vendor/github.com/prometheus/procfs/cpuinfo.go b/vendor/github.com/prometheus/procfs/cpuinfo.go index ff6b927da..f4f5501c6 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo.go @@ -79,7 +79,7 @@ func parseCPUInfoX86(info []byte) ([]CPUInfo, error) { // find the first "processor" line firstLine := firstNonEmptyLine(scanner) if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, firstLine) } field := strings.SplitN(firstLine, ": ", 2) v, err := strconv.ParseUint(field[1], 0, 32) @@ -192,9 +192,10 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) { scanner := bufio.NewScanner(bytes.NewReader(info)) firstLine := firstNonEmptyLine(scanner) - match, _ := regexp.MatchString("^[Pp]rocessor", firstLine) + match, err := regexp.MatchString("^[Pp]rocessor", firstLine) if !match || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%s: Cannot parse line: %q: %w", ErrFileParse, firstLine, err) + } field := strings.SplitN(firstLine, ": ", 2) cpuinfo := []CPUInfo{} @@ -258,7 +259,7 @@ func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) { firstLine := firstNonEmptyLine(scanner) if !strings.HasPrefix(firstLine, "vendor_id") || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, firstLine) } field := strings.SplitN(firstLine, ": ", 2) cpuinfo := []CPUInfo{} @@ -283,7 +284,7 @@ func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) { if strings.HasPrefix(line, "processor") { match := cpuinfoS390XProcessorRegexp.FindStringSubmatch(line) if len(match) < 2 { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine) } cpu := commonCPUInfo v, err := strconv.ParseUint(match[1], 0, 32) @@ -343,7 +344,7 @@ func parseCPUInfoMips(info []byte) ([]CPUInfo, error) { // find the first "processor" line firstLine := firstNonEmptyLine(scanner) if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine) } field := strings.SplitN(firstLine, ": ", 2) cpuinfo := []CPUInfo{} @@ -380,12 +381,48 @@ func parseCPUInfoMips(info []byte) ([]CPUInfo, error) { return cpuinfo, nil } +func parseCPUInfoLoong(info []byte) ([]CPUInfo, error) { + scanner := bufio.NewScanner(bytes.NewReader(info)) + // find the first "processor" line + firstLine := firstNonEmptyLine(scanner) + if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") { + return nil, errors.New("invalid cpuinfo file: " + firstLine) + } + field := strings.SplitN(firstLine, ": ", 2) + cpuinfo := []CPUInfo{} + systemType := field[1] + i := 0 + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, ":") { + continue + } + field := strings.SplitN(line, ": ", 2) + switch strings.TrimSpace(field[0]) { + case "processor": + v, err := strconv.ParseUint(field[1], 0, 32) + if err != nil { + return nil, err + } + i = int(v) + cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor + cpuinfo[i].Processor = uint(v) + cpuinfo[i].VendorID = systemType + case "CPU Family": + cpuinfo[i].CPUFamily = field[1] + case "Model Name": + cpuinfo[i].ModelName = field[1] + } + } + return cpuinfo, nil +} + func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) { scanner := bufio.NewScanner(bytes.NewReader(info)) firstLine := firstNonEmptyLine(scanner) if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine) } field := strings.SplitN(firstLine, ": ", 2) v, err := strconv.ParseUint(field[1], 0, 32) @@ -430,7 +467,7 @@ func parseCPUInfoRISCV(info []byte) ([]CPUInfo, error) { firstLine := firstNonEmptyLine(scanner) if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") { - return nil, fmt.Errorf("invalid cpuinfo file: %q", firstLine) + return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine) } field := strings.SplitN(firstLine, ": ", 2) v, err := strconv.ParseUint(field[1], 0, 32) diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go b/vendor/github.com/prometheus/procfs/cpuinfo_loong64.go similarity index 73% rename from vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go rename to vendor/github.com/prometheus/procfs/cpuinfo_loong64.go index c318385cb..d88442f0e 100644 --- a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_loong64.go @@ -1,10 +1,9 @@ -// Copyright 2013 Matt T. Proud -// +// Copyright 2022 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 +// 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, @@ -12,5 +11,9 @@ // 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 +//go:build linux +// +build linux + +package procfs + +var parseCPUInfo = parseCPUInfoLoong diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_others.go b/vendor/github.com/prometheus/procfs/cpuinfo_others.go index ea41bf2ca..a6b2b3127 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo_others.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo_others.go @@ -11,8 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build linux && !386 && !amd64 && !arm && !arm64 && !mips && !mips64 && !mips64le && !mipsle && !ppc64 && !ppc64le && !riscv64 && !s390x -// +build linux,!386,!amd64,!arm,!arm64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x +//go:build linux && !386 && !amd64 && !arm && !arm64 && !loong64 && !mips && !mips64 && !mips64le && !mipsle && !ppc64 && !ppc64le && !riscv64 && !s390x +// +build linux,!386,!amd64,!arm,!arm64,!loong64,!mips,!mips64,!mips64le,!mipsle,!ppc64,!ppc64le,!riscv64,!s390x package procfs diff --git a/vendor/github.com/prometheus/procfs/crypto.go b/vendor/github.com/prometheus/procfs/crypto.go index 5048ad1f2..9a73e2639 100644 --- a/vendor/github.com/prometheus/procfs/crypto.go +++ b/vendor/github.com/prometheus/procfs/crypto.go @@ -55,12 +55,13 @@ func (fs FS) Crypto() ([]Crypto, error) { path := fs.proc.Path("crypto") b, err := util.ReadFileNoStat(path) if err != nil { - return nil, fmt.Errorf("error reading crypto %q: %w", path, err) + return nil, fmt.Errorf("%s: Cannot read file %v: %w", ErrFileRead, b, err) + } crypto, err := parseCrypto(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("error parsing crypto %q: %w", path, err) + return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, crypto, err) } return crypto, nil @@ -83,7 +84,7 @@ func parseCrypto(r io.Reader) ([]Crypto, error) { kv := strings.Split(text, ":") if len(kv) != 2 { - return nil, fmt.Errorf("malformed crypto line: %q", text) + return nil, fmt.Errorf("%w: Cannot parae line: %q", ErrFileParse, text) } k := strings.TrimSpace(kv[0]) diff --git a/vendor/github.com/prometheus/procfs/doc.go b/vendor/github.com/prometheus/procfs/doc.go index d31a82600..f9d961e44 100644 --- a/vendor/github.com/prometheus/procfs/doc.go +++ b/vendor/github.com/prometheus/procfs/doc.go @@ -16,30 +16,29 @@ // // Example: // -// package main -// -// import ( -// "fmt" -// "log" -// -// "github.com/prometheus/procfs" -// ) -// -// func main() { -// p, err := procfs.Self() -// if err != nil { -// log.Fatalf("could not get process: %s", err) -// } -// -// stat, err := p.Stat() -// if err != nil { -// log.Fatalf("could not get process stat: %s", err) -// } -// -// fmt.Printf("command: %s\n", stat.Comm) -// fmt.Printf("cpu time: %fs\n", stat.CPUTime()) -// fmt.Printf("vsize: %dB\n", stat.VirtualMemory()) -// fmt.Printf("rss: %dB\n", stat.ResidentMemory()) -// } -// +// package main +// +// import ( +// "fmt" +// "log" +// +// "github.com/prometheus/procfs" +// ) +// +// func main() { +// p, err := procfs.Self() +// if err != nil { +// log.Fatalf("could not get process: %s", err) +// } +// +// stat, err := p.Stat() +// if err != nil { +// log.Fatalf("could not get process stat: %s", err) +// } +// +// fmt.Printf("command: %s\n", stat.Comm) +// fmt.Printf("cpu time: %fs\n", stat.CPUTime()) +// fmt.Printf("vsize: %dB\n", stat.VirtualMemory()) +// fmt.Printf("rss: %dB\n", stat.ResidentMemory()) +// } package procfs diff --git a/vendor/github.com/prometheus/procfs/fs.go b/vendor/github.com/prometheus/procfs/fs.go index 0102ab0fd..4980c875b 100644 --- a/vendor/github.com/prometheus/procfs/fs.go +++ b/vendor/github.com/prometheus/procfs/fs.go @@ -20,7 +20,8 @@ import ( // FS represents the pseudo-filesystem sys, which provides an interface to // kernel data structures. type FS struct { - proc fs.FS + proc fs.FS + isReal bool } // DefaultMountPoint is the common mount point of the proc filesystem. @@ -39,5 +40,11 @@ func NewFS(mountPoint string) (FS, error) { if err != nil { return FS{}, err } - return FS{fs}, nil + + isReal, err := isRealProc(mountPoint) + if err != nil { + return FS{}, err + } + + return FS{fs, isReal}, nil } diff --git a/vendor/github.com/prometheus/procfs/fs_statfs_notype.go b/vendor/github.com/prometheus/procfs/fs_statfs_notype.go new file mode 100644 index 000000000..134767d69 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fs_statfs_notype.go @@ -0,0 +1,23 @@ +// Copyright 2018 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. + +//go:build !freebsd && !linux +// +build !freebsd,!linux + +package procfs + +// isRealProc returns true on architectures that don't have a Type argument +// in their Statfs_t struct +func isRealProc(mountPoint string) (bool, error) { + return true, nil +} diff --git a/vendor/github.com/prometheus/procfs/fs_statfs_type.go b/vendor/github.com/prometheus/procfs/fs_statfs_type.go new file mode 100644 index 000000000..80df79c31 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fs_statfs_type.go @@ -0,0 +1,33 @@ +// Copyright 2018 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. + +//go:build freebsd || linux +// +build freebsd linux + +package procfs + +import ( + "syscall" +) + +// isRealProc determines whether supplied mountpoint is really a proc filesystem. +func isRealProc(mountPoint string) (bool, error) { + stat := syscall.Statfs_t{} + err := syscall.Statfs(mountPoint, &stat) + if err != nil { + return false, err + } + + // 0x9fa0 is PROC_SUPER_MAGIC: https://elixir.bootlin.com/linux/v6.1/source/include/uapi/linux/magic.h#L87 + return stat.Type == 0x9fa0, nil +} diff --git a/vendor/github.com/prometheus/procfs/fscache.go b/vendor/github.com/prometheus/procfs/fscache.go index f8070e6e2..f560a8db3 100644 --- a/vendor/github.com/prometheus/procfs/fscache.go +++ b/vendor/github.com/prometheus/procfs/fscache.go @@ -236,7 +236,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) { m, err := parseFscacheinfo(bytes.NewReader(b)) if err != nil { - return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %w", err) + return Fscacheinfo{}, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, m, err) } return *m, nil @@ -245,7 +245,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) { func setFSCacheFields(fields []string, setFields ...*uint64) error { var err error if len(fields) < len(setFields) { - return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields)) + return fmt.Errorf("%s: Expected %d, but got %d: %w", ErrFileParse, len(setFields), len(fields), err) } for i := range setFields { @@ -263,7 +263,7 @@ func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) { for s.Scan() { fields := strings.Fields(s.Text()) if len(fields) < 2 { - return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text()) + return nil, fmt.Errorf("%w: malformed Fscacheinfo line: %q", ErrFileParse, s.Text()) } switch fields[0] { diff --git a/vendor/github.com/prometheus/procfs/internal/util/parse.go b/vendor/github.com/prometheus/procfs/internal/util/parse.go index b030951fa..14272dc78 100644 --- a/vendor/github.com/prometheus/procfs/internal/util/parse.go +++ b/vendor/github.com/prometheus/procfs/internal/util/parse.go @@ -64,6 +64,21 @@ func ParsePInt64s(ss []string) ([]*int64, error) { return us, nil } +// Parses a uint64 from given hex in string. +func ParseHexUint64s(ss []string) ([]*uint64, error) { + us := make([]*uint64, 0, len(ss)) + for _, s := range ss { + u, err := strconv.ParseUint(s, 16, 64) + if err != nil { + return nil, err + } + + us = append(us, &u) + } + + return us, nil +} + // ReadUintFromFile reads a file and attempts to parse a uint64 from it. func ReadUintFromFile(path string) (uint64, error) { data, err := os.ReadFile(path) diff --git a/vendor/github.com/prometheus/procfs/ipvs.go b/vendor/github.com/prometheus/procfs/ipvs.go index 391c07957..5a145bbfe 100644 --- a/vendor/github.com/prometheus/procfs/ipvs.go +++ b/vendor/github.com/prometheus/procfs/ipvs.go @@ -221,15 +221,16 @@ func parseIPPort(s string) (net.IP, uint16, error) { case 46: ip = net.ParseIP(s[1:40]) if ip == nil { - return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40]) + return nil, 0, fmt.Errorf("%s: Invalid IPv6 addr %s: %w", ErrFileParse, s[1:40], err) } default: - return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s) + return nil, 0, fmt.Errorf("%s: Unexpected IP:Port %s: %w", ErrFileParse, s, err) } portString := s[len(s)-4:] if len(portString) != 4 { - return nil, 0, fmt.Errorf("unexpected port string format: %s", portString) + return nil, 0, + fmt.Errorf("%s: Unexpected port string format %s: %w", ErrFileParse, portString, err) } port, err := strconv.ParseUint(portString, 16, 16) if err != nil { diff --git a/vendor/github.com/prometheus/procfs/loadavg.go b/vendor/github.com/prometheus/procfs/loadavg.go index 0096cafbd..59465c5bb 100644 --- a/vendor/github.com/prometheus/procfs/loadavg.go +++ b/vendor/github.com/prometheus/procfs/loadavg.go @@ -44,14 +44,14 @@ func parseLoad(loadavgBytes []byte) (*LoadAvg, error) { loads := make([]float64, 3) parts := strings.Fields(string(loadavgBytes)) if len(parts) < 3 { - return nil, fmt.Errorf("malformed loadavg line: too few fields in loadavg string: %q", string(loadavgBytes)) + return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, string(loadavgBytes)) } var err error for i, load := range parts[0:3] { loads[i], err = strconv.ParseFloat(load, 64) if err != nil { - return nil, fmt.Errorf("could not parse load %q: %w", load, err) + return nil, fmt.Errorf("%s: Cannot parse load: %f: %w", ErrFileParse, loads[i], err) } } return &LoadAvg{ diff --git a/vendor/github.com/prometheus/procfs/mdstat.go b/vendor/github.com/prometheus/procfs/mdstat.go index a95c889cb..fdd4b9544 100644 --- a/vendor/github.com/prometheus/procfs/mdstat.go +++ b/vendor/github.com/prometheus/procfs/mdstat.go @@ -70,7 +70,7 @@ func (fs FS) MDStat() ([]MDStat, error) { } mdstat, err := parseMDStat(data) if err != nil { - return nil, fmt.Errorf("error parsing mdstat %q: %w", fs.proc.Path("mdstat"), err) + return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, fs.proc.Path("mdstat"), err) } return mdstat, nil } @@ -90,13 +90,13 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { deviceFields := strings.Fields(line) if len(deviceFields) < 3 { - return nil, fmt.Errorf("not enough fields in mdline (expected at least 3): %s", line) + return nil, fmt.Errorf("%s: Expected 3+ lines, got %q", ErrFileParse, line) } mdName := deviceFields[0] // mdx state := deviceFields[2] // active or inactive if len(lines) <= i+3 { - return nil, fmt.Errorf("error parsing %q: too few lines for md device", mdName) + return nil, fmt.Errorf("%w: Too few lines for md device: %q", ErrFileParse, mdName) } // Failed disks have the suffix (F) & Spare disks have the suffix (S). @@ -105,7 +105,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { active, total, down, size, err := evalStatusLine(lines[i], lines[i+1]) if err != nil { - return nil, fmt.Errorf("error parsing md device lines: %w", err) + return nil, fmt.Errorf("%s: Cannot parse md device lines: %v: %w", ErrFileParse, active, err) } syncLineIdx := i + 2 @@ -140,7 +140,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { } else { syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx]) if err != nil { - return nil, fmt.Errorf("error parsing sync line in md device %q: %w", mdName, err) + return nil, fmt.Errorf("%s: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err) } } } @@ -168,13 +168,13 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) { func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) { statusFields := strings.Fields(statusLine) if len(statusFields) < 1 { - return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q", statusLine) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) } sizeStr := statusFields[0] size, err = strconv.ParseInt(sizeStr, 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) } if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") { @@ -189,17 +189,17 @@ func evalStatusLine(deviceLine, statusLine string) (active, total, down, size in matches := statusLineRE.FindStringSubmatch(statusLine) if len(matches) != 5 { - return 0, 0, 0, 0, fmt.Errorf("couldn't find all the substring matches: %s", statusLine) + return 0, 0, 0, 0, fmt.Errorf("%s: Could not fild all substring matches %s: %w", ErrFileParse, statusLine, err) } total, err = strconv.ParseInt(matches[2], 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err) } active, err = strconv.ParseInt(matches[3], 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("unexpected statusLine %q: %w", statusLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected active %d: %w", ErrFileParse, active, err) } down = int64(strings.Count(matches[4], "_")) @@ -209,42 +209,42 @@ func evalStatusLine(deviceLine, statusLine string) (active, total, down, size in func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) { matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return 0, 0, 0, 0, fmt.Errorf("unexpected recoveryLine: %s", recoveryLine) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected recoveryLine %s: %w", ErrFileParse, recoveryLine, err) } syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64) if err != nil { - return 0, 0, 0, 0, fmt.Errorf("error parsing int from recoveryLine %q: %w", recoveryLine, err) + return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected parsing of recoveryLine %q: %w", ErrFileParse, recoveryLine, err) } // Get percentage complete matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return syncedBlocks, 0, 0, 0, fmt.Errorf("unexpected recoveryLine matching percentage: %s", recoveryLine) + return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine) } pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64) if err != nil { - return syncedBlocks, 0, 0, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err) + return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine) } // Get time expected left to complete matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return syncedBlocks, pct, 0, 0, fmt.Errorf("unexpected recoveryLine matching est. finish time: %s", recoveryLine) + return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine) } finish, err = strconv.ParseFloat(matches[1], 64) if err != nil { - return syncedBlocks, pct, 0, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err) + return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine) } // Get recovery speed matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine) if len(matches) != 2 { - return syncedBlocks, pct, finish, 0, fmt.Errorf("unexpected recoveryLine matching speed: %s", recoveryLine) + return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine) } speed, err = strconv.ParseFloat(matches[1], 64) if err != nil { - return syncedBlocks, pct, finish, 0, fmt.Errorf("error parsing float from recoveryLine %q: %w", recoveryLine, err) + return syncedBlocks, pct, finish, 0, fmt.Errorf("%s: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err) } return syncedBlocks, pct, finish, speed, nil diff --git a/vendor/github.com/prometheus/procfs/meminfo.go b/vendor/github.com/prometheus/procfs/meminfo.go index f65e174e5..eaf00e224 100644 --- a/vendor/github.com/prometheus/procfs/meminfo.go +++ b/vendor/github.com/prometheus/procfs/meminfo.go @@ -152,7 +152,7 @@ func (fs FS) Meminfo() (Meminfo, error) { m, err := parseMemInfo(bytes.NewReader(b)) if err != nil { - return Meminfo{}, fmt.Errorf("failed to parse meminfo: %w", err) + return Meminfo{}, fmt.Errorf("%s: %w", ErrFileParse, err) } return *m, nil @@ -165,7 +165,7 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) { // Each line has at least a name and value; we ignore the unit. fields := strings.Fields(s.Text()) if len(fields) < 2 { - return nil, fmt.Errorf("malformed meminfo line: %q", s.Text()) + return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text()) } v, err := strconv.ParseUint(fields[1], 0, 64) diff --git a/vendor/github.com/prometheus/procfs/mountinfo.go b/vendor/github.com/prometheus/procfs/mountinfo.go index 59f4d5055..388ebf396 100644 --- a/vendor/github.com/prometheus/procfs/mountinfo.go +++ b/vendor/github.com/prometheus/procfs/mountinfo.go @@ -78,11 +78,11 @@ func parseMountInfoString(mountString string) (*MountInfo, error) { mountInfo := strings.Split(mountString, " ") mountInfoLength := len(mountInfo) if mountInfoLength < 10 { - return nil, fmt.Errorf("couldn't find enough fields in mount string: %s", mountString) + return nil, fmt.Errorf("%w: Too few fields in mount string: %s", ErrFileParse, mountString) } if mountInfo[mountInfoLength-4] != "-" { - return nil, fmt.Errorf("couldn't find separator in expected field: %s", mountInfo[mountInfoLength-4]) + return nil, fmt.Errorf("%w: couldn't find separator in expected field: %s", ErrFileParse, mountInfo[mountInfoLength-4]) } mount := &MountInfo{ @@ -98,18 +98,18 @@ func parseMountInfoString(mountString string) (*MountInfo, error) { mount.MountID, err = strconv.Atoi(mountInfo[0]) if err != nil { - return nil, fmt.Errorf("failed to parse mount ID") + return nil, fmt.Errorf("%w: mount ID: %q", ErrFileParse, mount.MountID) } mount.ParentID, err = strconv.Atoi(mountInfo[1]) if err != nil { - return nil, fmt.Errorf("failed to parse parent ID") + return nil, fmt.Errorf("%w: parent ID: %q", ErrFileParse, mount.ParentID) } // Has optional fields, which is a space separated list of values. // Example: shared:2 master:7 if mountInfo[6] != "" { mount.OptionalFields, err = mountOptionsParseOptionalFields(mountInfo[6 : mountInfoLength-4]) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %w", ErrFileParse, err) } } return mount, nil diff --git a/vendor/github.com/prometheus/procfs/mountstats.go b/vendor/github.com/prometheus/procfs/mountstats.go index f7a828bb1..9d8af6db7 100644 --- a/vendor/github.com/prometheus/procfs/mountstats.go +++ b/vendor/github.com/prometheus/procfs/mountstats.go @@ -44,6 +44,14 @@ const ( fieldTransport11TCPLen = 13 fieldTransport11UDPLen = 10 + + // kernel version >= 4.14 MaxLen + // See: https://elixir.bootlin.com/linux/v6.4.8/source/net/sunrpc/xprtrdma/xprt_rdma.h#L393 + fieldTransport11RDMAMaxLen = 28 + + // kernel version <= 4.2 MinLen + // See: https://elixir.bootlin.com/linux/v4.2.8/source/net/sunrpc/xprtrdma/xprt_rdma.h#L331 + fieldTransport11RDMAMinLen = 20 ) // A Mount is a device mount parsed from /proc/[pid]/mountstats. @@ -186,6 +194,8 @@ type NFSOperationStats struct { CumulativeTotalResponseMilliseconds uint64 // Duration from when a request was enqueued to when it was completely handled. CumulativeTotalRequestMilliseconds uint64 + // The average time from the point the client sends RPC requests until it receives the response. + AverageRTTMilliseconds float64 // The count of operations that complete with tk_status < 0. These statuses usually indicate error conditions. Errors uint64 } @@ -231,6 +241,33 @@ type NFSTransportStats struct { // A running counter, incremented on each request as the current size of the // pending queue. CumulativePendingQueue uint64 + + // Stats below only available with stat version 1.1. + // Transport over RDMA + + // accessed when sending a call + ReadChunkCount uint64 + WriteChunkCount uint64 + ReplyChunkCount uint64 + TotalRdmaRequest uint64 + + // rarely accessed error counters + PullupCopyCount uint64 + HardwayRegisterCount uint64 + FailedMarshalCount uint64 + BadReplyCount uint64 + MrsRecovered uint64 + MrsOrphaned uint64 + MrsAllocated uint64 + EmptySendctxQ uint64 + + // accessed when receiving a reply + TotalRdmaReply uint64 + FixupCopyCount uint64 + ReplyWaitsForSend uint64 + LocalInvNeeded uint64 + NomsgCallCount uint64 + BcallCount uint64 } // parseMountStats parses a /proc/[pid]/mountstats file and returns a slice @@ -264,7 +301,7 @@ func parseMountStats(r io.Reader) ([]*Mount, error) { if len(ss) > deviceEntryLen { // Only NFSv3 and v4 are supported for parsing statistics if m.Type != nfs3Type && m.Type != nfs4Type { - return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type) + return nil, fmt.Errorf("%w: Cannot parse MountStats for %q", ErrFileParse, m.Type) } statVersion := strings.TrimPrefix(ss[8], statVersionPrefix) @@ -284,10 +321,11 @@ func parseMountStats(r io.Reader) ([]*Mount, error) { } // parseMount parses an entry in /proc/[pid]/mountstats in the format: -// device [device] mounted on [mount] with fstype [type] +// +// device [device] mounted on [mount] with fstype [type] func parseMount(ss []string) (*Mount, error) { if len(ss) < deviceEntryLen { - return nil, fmt.Errorf("invalid device entry: %v", ss) + return nil, fmt.Errorf("%w: Invalid device %q", ErrFileParse, ss) } // Check for specific words appearing at specific indices to ensure @@ -305,7 +343,7 @@ func parseMount(ss []string) (*Mount, error) { for _, f := range format { if ss[f.i] != f.s { - return nil, fmt.Errorf("invalid device entry: %v", ss) + return nil, fmt.Errorf("%w: Invalid device %q", ErrFileParse, ss) } } @@ -342,7 +380,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e switch ss[0] { case fieldOpts: if len(ss) < 2 { - return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) + return nil, fmt.Errorf("%w: Incomplete information for NFS stats: %v", ErrFileParse, ss) } if stats.Opts == nil { stats.Opts = map[string]string{} @@ -357,7 +395,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e } case fieldAge: if len(ss) < 2 { - return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) + return nil, fmt.Errorf("%w: Incomplete information for NFS stats: %v", ErrFileParse, ss) } // Age integer is in seconds d, err := time.ParseDuration(ss[1] + "s") @@ -368,7 +406,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e stats.Age = d case fieldBytes: if len(ss) < 2 { - return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) + return nil, fmt.Errorf("%w: Incomplete information for NFS stats: %v", ErrFileParse, ss) } bstats, err := parseNFSBytesStats(ss[1:]) if err != nil { @@ -378,7 +416,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e stats.Bytes = *bstats case fieldEvents: if len(ss) < 2 { - return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) + return nil, fmt.Errorf("%w: Incomplete information for NFS events: %v", ErrFileParse, ss) } estats, err := parseNFSEventsStats(ss[1:]) if err != nil { @@ -388,7 +426,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e stats.Events = *estats case fieldTransport: if len(ss) < 3 { - return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss) + return nil, fmt.Errorf("%w: Incomplete information for NFS transport stats: %v", ErrFileParse, ss) } tstats, err := parseNFSTransportStats(ss[1:], statVersion) @@ -427,7 +465,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e // integer fields. func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) { if len(ss) != fieldBytesLen { - return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss) + return nil, fmt.Errorf("%w: Invalid NFS bytes stats: %v", ErrFileParse, ss) } ns := make([]uint64, 0, fieldBytesLen) @@ -456,7 +494,7 @@ func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) { // integer fields. func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) { if len(ss) != fieldEventsLen { - return nil, fmt.Errorf("invalid NFS events stats: %v", ss) + return nil, fmt.Errorf("%w: invalid NFS events stats: %v", ErrFileParse, ss) } ns := make([]uint64, 0, fieldEventsLen) @@ -520,7 +558,7 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { } if len(ss) < minFields { - return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss) + return nil, fmt.Errorf("%w: invalid NFS per-operations stats: %v", ErrFileParse, ss) } // Skip string operation name for integers @@ -533,7 +571,6 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { ns = append(ns, n) } - opStats := NFSOperationStats{ Operation: strings.TrimSuffix(ss[0], ":"), Requests: ns[0], @@ -545,6 +582,9 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { CumulativeTotalResponseMilliseconds: ns[6], CumulativeTotalRequestMilliseconds: ns[7], } + if ns[0] != 0 { + opStats.AverageRTTMilliseconds = float64(ns[6]) / float64(ns[0]) + } if len(ns) > 8 { opStats.Errors = ns[8] @@ -571,10 +611,10 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats } else if protocol == "udp" { expectedLength = fieldTransport10UDPLen } else { - return nil, fmt.Errorf("invalid NFS protocol \"%s\" in stats 1.0 statement: %v", protocol, ss) + return nil, fmt.Errorf("%w: Invalid NFS protocol \"%s\" in stats 1.0 statement: %v", ErrFileParse, protocol, ss) } if len(ss) != expectedLength { - return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss) + return nil, fmt.Errorf("%w: Invalid NFS transport stats 1.0 statement: %v", ErrFileParse, ss) } case statVersion11: var expectedLength int @@ -582,14 +622,17 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats expectedLength = fieldTransport11TCPLen } else if protocol == "udp" { expectedLength = fieldTransport11UDPLen + } else if protocol == "rdma" { + expectedLength = fieldTransport11RDMAMinLen } else { - return nil, fmt.Errorf("invalid NFS protocol \"%s\" in stats 1.1 statement: %v", protocol, ss) + return nil, fmt.Errorf("%w: invalid NFS protocol \"%s\" in stats 1.1 statement: %v", ErrFileParse, protocol, ss) } - if len(ss) != expectedLength { - return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss) + if (len(ss) != expectedLength && (protocol == "tcp" || protocol == "udp")) || + (protocol == "rdma" && len(ss) < expectedLength) { + return nil, fmt.Errorf("%w: invalid NFS transport stats 1.1 statement: %v, protocol: %v", ErrFileParse, ss, protocol) } default: - return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion) + return nil, fmt.Errorf("%s: Unrecognized NFS transport stats version: %q, protocol: %v", ErrFileParse, statVersion, protocol) } // Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay @@ -599,7 +642,9 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats // Note: slice length must be set to length of v1.1 stats to avoid a panic when // only v1.0 stats are present. // See: https://github.com/prometheus/node_exporter/issues/571. - ns := make([]uint64, fieldTransport11TCPLen) + // + // Note: NFS Over RDMA slice length is fieldTransport11RDMAMaxLen + ns := make([]uint64, fieldTransport11RDMAMaxLen+3) for i, s := range ss { n, err := strconv.ParseUint(s, 10, 64) if err != nil { @@ -617,9 +662,14 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats // we set them to 0 here. if protocol == "udp" { ns = append(ns[:2], append(make([]uint64, 3), ns[2:]...)...) + } else if protocol == "tcp" { + ns = append(ns[:fieldTransport11TCPLen], make([]uint64, fieldTransport11RDMAMaxLen-fieldTransport11TCPLen+3)...) + } else if protocol == "rdma" { + ns = append(ns[:fieldTransport10TCPLen], append(make([]uint64, 3), ns[fieldTransport10TCPLen:]...)...) } return &NFSTransportStats{ + // NFS xprt over tcp or udp Protocol: protocol, Port: ns[0], Bind: ns[1], @@ -631,8 +681,32 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats BadTransactionIDs: ns[7], CumulativeActiveRequests: ns[8], CumulativeBacklog: ns[9], - MaximumRPCSlotsUsed: ns[10], - CumulativeSendingQueue: ns[11], - CumulativePendingQueue: ns[12], + + // NFS xprt over tcp or udp + // And statVersion 1.1 + MaximumRPCSlotsUsed: ns[10], + CumulativeSendingQueue: ns[11], + CumulativePendingQueue: ns[12], + + // NFS xprt over rdma + // And stat Version 1.1 + ReadChunkCount: ns[13], + WriteChunkCount: ns[14], + ReplyChunkCount: ns[15], + TotalRdmaRequest: ns[16], + PullupCopyCount: ns[17], + HardwayRegisterCount: ns[18], + FailedMarshalCount: ns[19], + BadReplyCount: ns[20], + MrsRecovered: ns[21], + MrsOrphaned: ns[22], + MrsAllocated: ns[23], + EmptySendctxQ: ns[24], + TotalRdmaReply: ns[25], + FixupCopyCount: ns[26], + ReplyWaitsForSend: ns[27], + LocalInvNeeded: ns[28], + NomsgCallCount: ns[29], + BcallCount: ns[30], }, nil } diff --git a/vendor/github.com/prometheus/procfs/net_conntrackstat.go b/vendor/github.com/prometheus/procfs/net_conntrackstat.go index 8300daca0..fdfa45611 100644 --- a/vendor/github.com/prometheus/procfs/net_conntrackstat.go +++ b/vendor/github.com/prometheus/procfs/net_conntrackstat.go @@ -18,7 +18,6 @@ import ( "bytes" "fmt" "io" - "strconv" "strings" "github.com/prometheus/procfs/internal/util" @@ -28,9 +27,13 @@ import ( // and contains netfilter conntrack statistics at one CPU core. type ConntrackStatEntry struct { Entries uint64 + Searched uint64 Found uint64 + New uint64 Invalid uint64 Ignore uint64 + Delete uint64 + DeleteList uint64 Insert uint64 InsertFailed uint64 Drop uint64 @@ -55,7 +58,7 @@ func readConntrackStat(path string) ([]ConntrackStatEntry, error) { stat, err := parseConntrackStat(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("failed to read conntrack stats from %q: %w", path, err) + return nil, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, path, err) } return stat, nil @@ -81,73 +84,35 @@ func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) { // Parses a ConntrackStatEntry from given array of fields. func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) { - if len(fields) != 17 { - return nil, fmt.Errorf("invalid conntrackstat entry, missing fields") - } - entry := &ConntrackStatEntry{} - - entries, err := parseConntrackStatField(fields[0]) - if err != nil { - return nil, err - } - entry.Entries = entries - - found, err := parseConntrackStatField(fields[2]) - if err != nil { - return nil, err - } - entry.Found = found - - invalid, err := parseConntrackStatField(fields[4]) - if err != nil { - return nil, err - } - entry.Invalid = invalid - - ignore, err := parseConntrackStatField(fields[5]) - if err != nil { - return nil, err - } - entry.Ignore = ignore - - insert, err := parseConntrackStatField(fields[8]) + entries, err := util.ParseHexUint64s(fields) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: Cannot parse entry: %d: %w", ErrFileParse, entries, err) } - entry.Insert = insert - - insertFailed, err := parseConntrackStatField(fields[9]) - if err != nil { - return nil, err + numEntries := len(entries) + if numEntries < 16 || numEntries > 17 { + return nil, + fmt.Errorf("%w: invalid conntrackstat entry, invalid number of fields: %d", ErrFileParse, numEntries) } - entry.InsertFailed = insertFailed - drop, err := parseConntrackStatField(fields[10]) - if err != nil { - return nil, err + stats := &ConntrackStatEntry{ + Entries: *entries[0], + Searched: *entries[1], + Found: *entries[2], + New: *entries[3], + Invalid: *entries[4], + Ignore: *entries[5], + Delete: *entries[6], + DeleteList: *entries[7], + Insert: *entries[8], + InsertFailed: *entries[9], + Drop: *entries[10], + EarlyDrop: *entries[11], } - entry.Drop = drop - earlyDrop, err := parseConntrackStatField(fields[11]) - if err != nil { - return nil, err + // Ignore missing search_restart on Linux < 2.6.35. + if numEntries == 17 { + stats.SearchRestart = *entries[16] } - entry.EarlyDrop = earlyDrop - searchRestart, err := parseConntrackStatField(fields[16]) - if err != nil { - return nil, err - } - entry.SearchRestart = searchRestart - - return entry, nil -} - -// Parses a uint64 from given hex in string. -func parseConntrackStatField(field string) (uint64, error) { - val, err := strconv.ParseUint(field, 16, 64) - if err != nil { - return 0, fmt.Errorf("couldn't parse %q field: %w", field, err) - } - return val, err + return stats, nil } diff --git a/vendor/github.com/prometheus/procfs/net_ip_socket.go b/vendor/github.com/prometheus/procfs/net_ip_socket.go index 7fd57d7f4..4da81ea57 100644 --- a/vendor/github.com/prometheus/procfs/net_ip_socket.go +++ b/vendor/github.com/prometheus/procfs/net_ip_socket.go @@ -130,7 +130,7 @@ func parseIP(hexIP string) (net.IP, error) { var byteIP []byte byteIP, err := hex.DecodeString(hexIP) if err != nil { - return nil, fmt.Errorf("cannot parse address field in socket line %q", hexIP) + return nil, fmt.Errorf("%s: Cannot parse socket field in %q: %w", ErrFileParse, hexIP, err) } switch len(byteIP) { case 4: @@ -144,7 +144,7 @@ func parseIP(hexIP string) (net.IP, error) { } return i, nil default: - return nil, fmt.Errorf("Unable to parse IP %s", hexIP) + return nil, fmt.Errorf("%s: Unable to parse IP %s: %w", ErrFileParse, hexIP, nil) } } @@ -153,7 +153,8 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) { line := &netIPSocketLine{} if len(fields) < 10 { return nil, fmt.Errorf( - "cannot parse net socket line as it has less then 10 columns %q", + "%w: Less than 10 columns found %q", + ErrFileParse, strings.Join(fields, " "), ) } @@ -162,64 +163,65 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) { // sl s := strings.Split(fields[0], ":") if len(s) != 2 { - return nil, fmt.Errorf("cannot parse sl field in socket line %q", fields[0]) + return nil, fmt.Errorf("%w: Unable to parse sl field in line %q", ErrFileParse, fields[0]) } if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil { - return nil, fmt.Errorf("cannot parse sl value in socket line: %w", err) + return nil, fmt.Errorf("%s: Unable to parse sl field in %q: %w", ErrFileParse, line.Sl, err) } // local_address l := strings.Split(fields[1], ":") if len(l) != 2 { - return nil, fmt.Errorf("cannot parse local_address field in socket line %q", fields[1]) + return nil, fmt.Errorf("%w: Unable to parse local_address field in %q", ErrFileParse, fields[1]) } if line.LocalAddr, err = parseIP(l[0]); err != nil { return nil, err } if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil { - return nil, fmt.Errorf("cannot parse local_address port value in socket line: %w", err) + return nil, fmt.Errorf("%s: Unable to parse local_address port value line %q: %w", ErrFileParse, line.LocalPort, err) } // remote_address r := strings.Split(fields[2], ":") if len(r) != 2 { - return nil, fmt.Errorf("cannot parse rem_address field in socket line %q", fields[1]) + return nil, fmt.Errorf("%w: Unable to parse rem_address field in %q", ErrFileParse, fields[1]) } if line.RemAddr, err = parseIP(r[0]); err != nil { return nil, err } if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil { - return nil, fmt.Errorf("cannot parse rem_address port value in socket line: %w", err) + return nil, fmt.Errorf("%s: Cannot parse rem_address port value in %q: %w", ErrFileParse, line.RemPort, err) } // st if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil { - return nil, fmt.Errorf("cannot parse st value in socket line: %w", err) + return nil, fmt.Errorf("%s: Cannot parse st value in %q: %w", ErrFileParse, line.St, err) } // tx_queue and rx_queue q := strings.Split(fields[4], ":") if len(q) != 2 { return nil, fmt.Errorf( - "cannot parse tx/rx queues in socket line as it has a missing colon %q", + "%w: Missing colon for tx/rx queues in socket line %q", + ErrFileParse, fields[4], ) } if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil { - return nil, fmt.Errorf("cannot parse tx_queue value in socket line: %w", err) + return nil, fmt.Errorf("%s: Cannot parse tx_queue value in %q: %w", ErrFileParse, line.TxQueue, err) } if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil { - return nil, fmt.Errorf("cannot parse rx_queue value in socket line: %w", err) + return nil, fmt.Errorf("%s: Cannot parse trx_queue value in %q: %w", ErrFileParse, line.RxQueue, err) } // uid if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil { - return nil, fmt.Errorf("cannot parse uid value in socket line: %w", err) + return nil, fmt.Errorf("%s: Cannot parse UID value in %q: %w", ErrFileParse, line.UID, err) } // inode if line.Inode, err = strconv.ParseUint(fields[9], 0, 64); err != nil { - return nil, fmt.Errorf("cannot parse inode value in socket line: %w", err) + return nil, fmt.Errorf("%s: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err) } return line, nil diff --git a/vendor/github.com/prometheus/procfs/net_protocols.go b/vendor/github.com/prometheus/procfs/net_protocols.go index 374b6f73f..b6c77b709 100644 --- a/vendor/github.com/prometheus/procfs/net_protocols.go +++ b/vendor/github.com/prometheus/procfs/net_protocols.go @@ -131,7 +131,7 @@ func (ps NetProtocolStats) parseLine(rawLine string) (*NetProtocolStatLine, erro } else if fields[6] == disabled { line.Slab = false } else { - return nil, fmt.Errorf("unable to parse capability for protocol: %s", line.Name) + return nil, fmt.Errorf("%w: capability for protocol: %s", ErrFileParse, line.Name) } line.ModuleName = fields[7] @@ -173,7 +173,7 @@ func (pc *NetProtocolCapabilities) parseCapabilities(capabilities []string) erro } else if capabilities[i] == "n" { *capabilityFields[i] = false } else { - return fmt.Errorf("unable to parse capability block for protocol: position %d", i) + return fmt.Errorf("%w: capability block for protocol: position %d", ErrFileParse, i) } } return nil diff --git a/vendor/github.com/prometheus/procfs/net_route.go b/vendor/github.com/prometheus/procfs/net_route.go new file mode 100644 index 000000000..deb7029fe --- /dev/null +++ b/vendor/github.com/prometheus/procfs/net_route.go @@ -0,0 +1,143 @@ +// Copyright 2023 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 procfs + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +const ( + blackholeRepresentation string = "*" + blackholeIfaceName string = "blackhole" + routeLineColumns int = 11 +) + +// A NetRouteLine represents one line from net/route. +type NetRouteLine struct { + Iface string + Destination uint32 + Gateway uint32 + Flags uint32 + RefCnt uint32 + Use uint32 + Metric uint32 + Mask uint32 + MTU uint32 + Window uint32 + IRTT uint32 +} + +func (fs FS) NetRoute() ([]NetRouteLine, error) { + return readNetRoute(fs.proc.Path("net", "route")) +} + +func readNetRoute(path string) ([]NetRouteLine, error) { + b, err := util.ReadFileNoStat(path) + if err != nil { + return nil, err + } + + routelines, err := parseNetRoute(bytes.NewReader(b)) + if err != nil { + return nil, fmt.Errorf("failed to read net route from %s: %w", path, err) + } + return routelines, nil +} + +func parseNetRoute(r io.Reader) ([]NetRouteLine, error) { + var routelines []NetRouteLine + + scanner := bufio.NewScanner(r) + scanner.Scan() + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + routeline, err := parseNetRouteLine(fields) + if err != nil { + return nil, err + } + routelines = append(routelines, *routeline) + } + return routelines, nil +} + +func parseNetRouteLine(fields []string) (*NetRouteLine, error) { + if len(fields) != routeLineColumns { + return nil, fmt.Errorf("invalid routeline, num of digits: %d", len(fields)) + } + iface := fields[0] + if iface == blackholeRepresentation { + iface = blackholeIfaceName + } + destination, err := strconv.ParseUint(fields[1], 16, 32) + if err != nil { + return nil, err + } + gateway, err := strconv.ParseUint(fields[2], 16, 32) + if err != nil { + return nil, err + } + flags, err := strconv.ParseUint(fields[3], 10, 32) + if err != nil { + return nil, err + } + refcnt, err := strconv.ParseUint(fields[4], 10, 32) + if err != nil { + return nil, err + } + use, err := strconv.ParseUint(fields[5], 10, 32) + if err != nil { + return nil, err + } + metric, err := strconv.ParseUint(fields[6], 10, 32) + if err != nil { + return nil, err + } + mask, err := strconv.ParseUint(fields[7], 16, 32) + if err != nil { + return nil, err + } + mtu, err := strconv.ParseUint(fields[8], 10, 32) + if err != nil { + return nil, err + } + window, err := strconv.ParseUint(fields[9], 10, 32) + if err != nil { + return nil, err + } + irtt, err := strconv.ParseUint(fields[10], 10, 32) + if err != nil { + return nil, err + } + routeline := &NetRouteLine{ + Iface: iface, + Destination: uint32(destination), + Gateway: uint32(gateway), + Flags: uint32(flags), + RefCnt: uint32(refcnt), + Use: uint32(use), + Metric: uint32(metric), + Mask: uint32(mask), + MTU: uint32(mtu), + Window: uint32(window), + IRTT: uint32(irtt), + } + return routeline, nil +} diff --git a/vendor/github.com/prometheus/procfs/net_sockstat.go b/vendor/github.com/prometheus/procfs/net_sockstat.go index e36f4872d..360e36af7 100644 --- a/vendor/github.com/prometheus/procfs/net_sockstat.go +++ b/vendor/github.com/prometheus/procfs/net_sockstat.go @@ -16,7 +16,6 @@ package procfs import ( "bufio" "bytes" - "errors" "fmt" "io" "strings" @@ -70,7 +69,7 @@ func readSockstat(name string) (*NetSockstat, error) { stat, err := parseSockstat(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("failed to read sockstats from %q: %w", name, err) + return nil, fmt.Errorf("%s: sockstats from %q: %w", ErrFileRead, name, err) } return stat, nil @@ -84,13 +83,13 @@ func parseSockstat(r io.Reader) (*NetSockstat, error) { // Expect a minimum of a protocol and one key/value pair. fields := strings.Split(s.Text(), " ") if len(fields) < 3 { - return nil, fmt.Errorf("malformed sockstat line: %q", s.Text()) + return nil, fmt.Errorf("%w: Malformed sockstat line: %q", ErrFileParse, s.Text()) } // The remaining fields are key/value pairs. kvs, err := parseSockstatKVs(fields[1:]) if err != nil { - return nil, fmt.Errorf("error parsing sockstat key/value pairs from %q: %w", s.Text(), err) + return nil, fmt.Errorf("%s: sockstat key/value pairs from %q: %w", ErrFileParse, s.Text(), err) } // The first field is the protocol. We must trim its colon suffix. @@ -119,7 +118,7 @@ func parseSockstat(r io.Reader) (*NetSockstat, error) { // parseSockstatKVs parses a string slice into a map of key/value pairs. func parseSockstatKVs(kvs []string) (map[string]int, error) { if len(kvs)%2 != 0 { - return nil, errors.New("odd number of fields in key/value pairs") + return nil, fmt.Errorf("%w:: Odd number of fields in key/value pairs %q", ErrFileParse, kvs) } // Iterate two values at a time to gather key/value pairs. diff --git a/vendor/github.com/prometheus/procfs/net_softnet.go b/vendor/github.com/prometheus/procfs/net_softnet.go index a94f86dc4..c77085291 100644 --- a/vendor/github.com/prometheus/procfs/net_softnet.go +++ b/vendor/github.com/prometheus/procfs/net_softnet.go @@ -27,8 +27,9 @@ import ( // For the proc file format details, // See: // * Linux 2.6.23 https://elixir.bootlin.com/linux/v2.6.23/source/net/core/dev.c#L2343 -// * Linux 4.17 https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162 -// and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810. +// * Linux 2.6.39 https://elixir.bootlin.com/linux/v2.6.39/source/net/core/dev.c#L4086 +// * Linux 4.18 https://elixir.bootlin.com/linux/v4.18/source/net/core/net-procfs.c#L162 +// * Linux 5.14 https://elixir.bootlin.com/linux/v5.14/source/net/core/net-procfs.c#L169 // SoftnetStat contains a single row of data from /proc/net/softnet_stat. type SoftnetStat struct { @@ -38,6 +39,18 @@ type SoftnetStat struct { Dropped uint32 // Number of times processing packets ran out of quota. TimeSqueezed uint32 + // Number of collision occur while obtaining device lock while transmitting. + CPUCollision uint32 + // Number of times cpu woken up received_rps. + ReceivedRps uint32 + // number of times flow limit has been reached. + FlowLimitCount uint32 + // Softnet backlog status. + SoftnetBacklogLen uint32 + // CPU id owning this softnet_data. + Index uint32 + // softnet_data's Width. + Width int } var softNetProcFile = "net/softnet_stat" @@ -51,7 +64,7 @@ func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) { entries, err := parseSoftnet(bytes.NewReader(b)) if err != nil { - return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %w", err) + return nil, fmt.Errorf("%s: /proc/net/softnet_stat: %w", ErrFileParse, err) } return entries, nil @@ -63,25 +76,65 @@ func parseSoftnet(r io.Reader) ([]SoftnetStat, error) { s := bufio.NewScanner(r) var stats []SoftnetStat + cpuIndex := 0 for s.Scan() { columns := strings.Fields(s.Text()) width := len(columns) + softnetStat := SoftnetStat{} if width < minColumns { - return nil, fmt.Errorf("%d columns were detected, but at least %d were expected", width, minColumns) + return nil, fmt.Errorf("%w: detected %d columns, but expected at least %d", ErrFileParse, width, minColumns) } - // We only parse the first three columns at the moment. - us, err := parseHexUint32s(columns[0:3]) - if err != nil { - return nil, err + // Linux 2.6.23 https://elixir.bootlin.com/linux/v2.6.23/source/net/core/dev.c#L2347 + if width >= minColumns { + us, err := parseHexUint32s(columns[0:9]) + if err != nil { + return nil, err + } + + softnetStat.Processed = us[0] + softnetStat.Dropped = us[1] + softnetStat.TimeSqueezed = us[2] + softnetStat.CPUCollision = us[8] + } + + // Linux 2.6.39 https://elixir.bootlin.com/linux/v2.6.39/source/net/core/dev.c#L4086 + if width >= 10 { + us, err := parseHexUint32s(columns[9:10]) + if err != nil { + return nil, err + } + + softnetStat.ReceivedRps = us[0] } - stats = append(stats, SoftnetStat{ - Processed: us[0], - Dropped: us[1], - TimeSqueezed: us[2], - }) + // Linux 4.18 https://elixir.bootlin.com/linux/v4.18/source/net/core/net-procfs.c#L162 + if width >= 11 { + us, err := parseHexUint32s(columns[10:11]) + if err != nil { + return nil, err + } + + softnetStat.FlowLimitCount = us[0] + } + + // Linux 5.14 https://elixir.bootlin.com/linux/v5.14/source/net/core/net-procfs.c#L169 + if width >= 13 { + us, err := parseHexUint32s(columns[11:13]) + if err != nil { + return nil, err + } + + softnetStat.SoftnetBacklogLen = us[0] + softnetStat.Index = us[1] + } else { + // For older kernels, create the Index based on the scan line number. + softnetStat.Index = uint32(cpuIndex) + } + softnetStat.Width = width + stats = append(stats, softnetStat) + cpuIndex++ } return stats, nil diff --git a/vendor/github.com/prometheus/procfs/net_unix.go b/vendor/github.com/prometheus/procfs/net_unix.go index 98aa8e1c3..acbbc57ea 100644 --- a/vendor/github.com/prometheus/procfs/net_unix.go +++ b/vendor/github.com/prometheus/procfs/net_unix.go @@ -108,14 +108,14 @@ func parseNetUNIX(r io.Reader) (*NetUNIX, error) { line := s.Text() item, err := nu.parseLine(line, hasInode, minFields) if err != nil { - return nil, fmt.Errorf("failed to parse /proc/net/unix data %q: %w", line, err) + return nil, fmt.Errorf("%s: /proc/net/unix encountered data %q: %w", ErrFileParse, line, err) } nu.Rows = append(nu.Rows, item) } if err := s.Err(); err != nil { - return nil, fmt.Errorf("failed to scan /proc/net/unix data: %w", err) + return nil, fmt.Errorf("%s: /proc/net/unix encountered data: %w", ErrFileParse, err) } return &nu, nil @@ -126,7 +126,7 @@ func (u *NetUNIX) parseLine(line string, hasInode bool, min int) (*NetUNIXLine, l := len(fields) if l < min { - return nil, fmt.Errorf("expected at least %d fields but got %d", min, l) + return nil, fmt.Errorf("%w: expected at least %d fields but got %d", ErrFileParse, min, l) } // Field offsets are as follows: @@ -136,29 +136,29 @@ func (u *NetUNIX) parseLine(line string, hasInode bool, min int) (*NetUNIXLine, users, err := u.parseUsers(fields[1]) if err != nil { - return nil, fmt.Errorf("failed to parse ref count %q: %w", fields[1], err) + return nil, fmt.Errorf("%s: ref count %q: %w", ErrFileParse, fields[1], err) } flags, err := u.parseFlags(fields[3]) if err != nil { - return nil, fmt.Errorf("failed to parse flags %q: %w", fields[3], err) + return nil, fmt.Errorf("%s: Unable to parse flags %q: %w", ErrFileParse, fields[3], err) } typ, err := u.parseType(fields[4]) if err != nil { - return nil, fmt.Errorf("failed to parse type %q: %w", fields[4], err) + return nil, fmt.Errorf("%s: Failed to parse type %q: %w", ErrFileParse, fields[4], err) } state, err := u.parseState(fields[5]) if err != nil { - return nil, fmt.Errorf("failed to parse state %q: %w", fields[5], err) + return nil, fmt.Errorf("%s: Failed to parse state %q: %w", ErrFileParse, fields[5], err) } var inode uint64 if hasInode { inode, err = u.parseInode(fields[6]) if err != nil { - return nil, fmt.Errorf("failed to parse inode %q: %w", fields[6], err) + return nil, fmt.Errorf("%s failed to parse inode %q: %w", ErrFileParse, fields[6], err) } } diff --git a/vendor/github.com/prometheus/procfs/net_wireless.go b/vendor/github.com/prometheus/procfs/net_wireless.go new file mode 100644 index 000000000..7443edca9 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/net_wireless.go @@ -0,0 +1,182 @@ +// Copyright 2023 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 procfs + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// Wireless models the content of /proc/net/wireless. +type Wireless struct { + Name string + + // Status is the current 4-digit hex value status of the interface. + Status uint64 + + // QualityLink is the link quality. + QualityLink int + + // QualityLevel is the signal gain (dBm). + QualityLevel int + + // QualityNoise is the signal noise baseline (dBm). + QualityNoise int + + // DiscardedNwid is the number of discarded packets with wrong nwid/essid. + DiscardedNwid int + + // DiscardedCrypt is the number of discarded packets with wrong code/decode (WEP). + DiscardedCrypt int + + // DiscardedFrag is the number of discarded packets that can't perform MAC reassembly. + DiscardedFrag int + + // DiscardedRetry is the number of discarded packets that reached max MAC retries. + DiscardedRetry int + + // DiscardedMisc is the number of discarded packets for other reasons. + DiscardedMisc int + + // MissedBeacon is the number of missed beacons/superframe. + MissedBeacon int +} + +// Wireless returns kernel wireless statistics. +func (fs FS) Wireless() ([]*Wireless, error) { + b, err := util.ReadFileNoStat(fs.proc.Path("net/wireless")) + if err != nil { + return nil, err + } + + m, err := parseWireless(bytes.NewReader(b)) + if err != nil { + return nil, fmt.Errorf("%s: wireless: %w", ErrFileParse, err) + } + + return m, nil +} + +// parseWireless parses the contents of /proc/net/wireless. +/* +Inter-| sta-| Quality | Discarded packets | Missed | WE +face | tus | link level noise | nwid crypt frag retry misc | beacon | 22 + eth1: 0000 5. -256. -10. 0 1 0 3 0 0 + eth2: 0000 5. -256. -20. 0 2 0 4 0 0 +*/ +func parseWireless(r io.Reader) ([]*Wireless, error) { + var ( + interfaces []*Wireless + scanner = bufio.NewScanner(r) + ) + + for n := 0; scanner.Scan(); n++ { + // Skip the 2 header lines. + if n < 2 { + continue + } + + line := scanner.Text() + + parts := strings.Split(line, ":") + if len(parts) != 2 { + return nil, fmt.Errorf("%w: expected 2 parts after splitting line by ':', got %d for line %q", ErrFileParse, len(parts), line) + } + + name := strings.TrimSpace(parts[0]) + stats := strings.Fields(parts[1]) + + if len(stats) < 10 { + return nil, fmt.Errorf("%w: invalid number of fields in line %d, expected 10+, got %d: %q", ErrFileParse, n, len(stats), line) + } + + status, err := strconv.ParseUint(stats[0], 16, 16) + if err != nil { + return nil, fmt.Errorf("%w: invalid status in line %d: %q", ErrFileParse, n, line) + } + + qlink, err := strconv.Atoi(strings.TrimSuffix(stats[1], ".")) + if err != nil { + return nil, fmt.Errorf("%s: parse Quality:link as integer %q: %w", ErrFileParse, qlink, err) + } + + qlevel, err := strconv.Atoi(strings.TrimSuffix(stats[2], ".")) + if err != nil { + return nil, fmt.Errorf("%s: Quality:level as integer %q: %w", ErrFileParse, qlevel, err) + } + + qnoise, err := strconv.Atoi(strings.TrimSuffix(stats[3], ".")) + if err != nil { + return nil, fmt.Errorf("%s: Quality:noise as integer %q: %w", ErrFileParse, qnoise, err) + } + + dnwid, err := strconv.Atoi(stats[4]) + if err != nil { + return nil, fmt.Errorf("%s: Discarded:nwid as integer %q: %w", ErrFileParse, dnwid, err) + } + + dcrypt, err := strconv.Atoi(stats[5]) + if err != nil { + return nil, fmt.Errorf("%s: Discarded:crypt as integer %q: %w", ErrFileParse, dcrypt, err) + } + + dfrag, err := strconv.Atoi(stats[6]) + if err != nil { + return nil, fmt.Errorf("%s: Discarded:frag as integer %q: %w", ErrFileParse, dfrag, err) + } + + dretry, err := strconv.Atoi(stats[7]) + if err != nil { + return nil, fmt.Errorf("%s: Discarded:retry as integer %q: %w", ErrFileParse, dretry, err) + } + + dmisc, err := strconv.Atoi(stats[8]) + if err != nil { + return nil, fmt.Errorf("%s: Discarded:misc as integer %q: %w", ErrFileParse, dmisc, err) + } + + mbeacon, err := strconv.Atoi(stats[9]) + if err != nil { + return nil, fmt.Errorf("%s: Missed:beacon as integer %q: %w", ErrFileParse, mbeacon, err) + } + + w := &Wireless{ + Name: name, + Status: status, + QualityLink: qlink, + QualityLevel: qlevel, + QualityNoise: qnoise, + DiscardedNwid: dnwid, + DiscardedCrypt: dcrypt, + DiscardedFrag: dfrag, + DiscardedRetry: dretry, + DiscardedMisc: dmisc, + MissedBeacon: mbeacon, + } + + interfaces = append(interfaces, w) + } + + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("%s: Failed to scan /proc/net/wireless: %w", ErrFileRead, err) + } + + return interfaces, nil +} diff --git a/vendor/github.com/prometheus/procfs/net_xfrm.go b/vendor/github.com/prometheus/procfs/net_xfrm.go index f9d9d243d..932ef2046 100644 --- a/vendor/github.com/prometheus/procfs/net_xfrm.go +++ b/vendor/github.com/prometheus/procfs/net_xfrm.go @@ -115,7 +115,7 @@ func (fs FS) NewXfrmStat() (XfrmStat, error) { fields := strings.Fields(s.Text()) if len(fields) != 2 { - return XfrmStat{}, fmt.Errorf("couldn't parse %q line %q", file.Name(), s.Text()) + return XfrmStat{}, fmt.Errorf("%w: %q line %q", ErrFileParse, file.Name(), s.Text()) } name := fields[0] diff --git a/vendor/github.com/prometheus/procfs/netstat.go b/vendor/github.com/prometheus/procfs/netstat.go index dcea9c5a6..742dff453 100644 --- a/vendor/github.com/prometheus/procfs/netstat.go +++ b/vendor/github.com/prometheus/procfs/netstat.go @@ -37,32 +37,46 @@ func (fs FS) NetStat() ([]NetStat, error) { var netStatsTotal []NetStat for _, filePath := range statFiles { - file, err := os.Open(filePath) + procNetstat, err := parseNetstat(filePath) if err != nil { return nil, err } + procNetstat.Filename = filepath.Base(filePath) - netStatFile := NetStat{ - Filename: filepath.Base(filePath), - Stats: make(map[string][]uint64), - } - scanner := bufio.NewScanner(file) - scanner.Scan() - // First string is always a header for stats - var headers []string - headers = append(headers, strings.Fields(scanner.Text())...) + netStatsTotal = append(netStatsTotal, procNetstat) + } + return netStatsTotal, nil +} + +// parseNetstat parses the metrics from `/proc/net/stat/` file +// and returns a NetStat structure. +func parseNetstat(filePath string) (NetStat, error) { + netStat := NetStat{ + Stats: make(map[string][]uint64), + } + file, err := os.Open(filePath) + if err != nil { + return netStat, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + scanner.Scan() - // Other strings represent per-CPU counters - for scanner.Scan() { - for num, counter := range strings.Fields(scanner.Text()) { - value, err := strconv.ParseUint(counter, 16, 64) - if err != nil { - return nil, err - } - netStatFile.Stats[headers[num]] = append(netStatFile.Stats[headers[num]], value) + // First string is always a header for stats + var headers []string + headers = append(headers, strings.Fields(scanner.Text())...) + + // Other strings represent per-CPU counters + for scanner.Scan() { + for num, counter := range strings.Fields(scanner.Text()) { + value, err := strconv.ParseUint(counter, 16, 64) + if err != nil { + return NetStat{}, err } + netStat.Stats[headers[num]] = append(netStat.Stats[headers[num]], value) } - netStatsTotal = append(netStatsTotal, netStatFile) } - return netStatsTotal, nil + + return netStat, nil } diff --git a/vendor/github.com/prometheus/procfs/proc.go b/vendor/github.com/prometheus/procfs/proc.go index c30223af7..d1f71caa5 100644 --- a/vendor/github.com/prometheus/procfs/proc.go +++ b/vendor/github.com/prometheus/procfs/proc.go @@ -15,13 +15,13 @@ package procfs import ( "bytes" + "errors" "fmt" "io" "os" "strconv" "strings" - "github.com/prometheus/procfs/internal/fs" "github.com/prometheus/procfs/internal/util" ) @@ -30,12 +30,18 @@ type Proc struct { // The process ID. PID int - fs fs.FS + fs FS } // Procs represents a list of Proc structs. type Procs []Proc +var ( + ErrFileParse = errors.New("Error Parsing File") + ErrFileRead = errors.New("Error Reading File") + ErrMountPoint = errors.New("Error Accessing Mount point") +) + func (p Procs) Len() int { return len(p) } func (p Procs) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID } @@ -43,7 +49,7 @@ func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID } // Self returns a process for the current process read via /proc/self. func Self() (Proc, error) { fs, err := NewFS(DefaultMountPoint) - if err != nil { + if err != nil || errors.Unwrap(err) == ErrMountPoint { return Proc{}, err } return fs.Self() @@ -92,7 +98,7 @@ func (fs FS) Proc(pid int) (Proc, error) { if _, err := os.Stat(fs.proc.Path(strconv.Itoa(pid))); err != nil { return Proc{}, err } - return Proc{PID: pid, fs: fs.proc}, nil + return Proc{PID: pid, fs: fs}, nil } // AllProcs returns a list of all currently available processes. @@ -105,7 +111,7 @@ func (fs FS) AllProcs() (Procs, error) { names, err := d.Readdirnames(-1) if err != nil { - return Procs{}, fmt.Errorf("could not read %q: %w", d.Name(), err) + return Procs{}, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, names, err) } p := Procs{} @@ -114,7 +120,7 @@ func (fs FS) AllProcs() (Procs, error) { if err != nil { continue } - p = append(p, Proc{PID: int(pid), fs: fs.proc}) + p = append(p, Proc{PID: int(pid), fs: fs}) } return p, nil @@ -206,7 +212,7 @@ func (p Proc) FileDescriptors() ([]uintptr, error) { for i, n := range names { fd, err := strconv.ParseInt(n, 10, 32) if err != nil { - return nil, fmt.Errorf("could not parse fd %q: %w", n, err) + return nil, fmt.Errorf("%s: Cannot parse line: %v: %w", ErrFileParse, i, err) } fds[i] = uintptr(fd) } @@ -237,6 +243,19 @@ func (p Proc) FileDescriptorTargets() ([]string, error) { // FileDescriptorsLen returns the number of currently open file descriptors of // a process. func (p Proc) FileDescriptorsLen() (int, error) { + // Use fast path if available (Linux v6.2): https://github.com/torvalds/linux/commit/f1f1f2569901 + if p.fs.isReal { + stat, err := os.Stat(p.path("fd")) + if err != nil { + return 0, err + } + + size := stat.Size() + if size > 0 { + return int(size), nil + } + } + fds, err := p.fileDescriptors() if err != nil { return 0, err @@ -278,14 +297,14 @@ func (p Proc) fileDescriptors() ([]string, error) { names, err := d.Readdirnames(-1) if err != nil { - return nil, fmt.Errorf("could not read %q: %w", d.Name(), err) + return nil, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, names, err) } return names, nil } func (p Proc) path(pa ...string) string { - return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...) + return p.fs.proc.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...) } // FileDescriptorsInfo retrieves information about all file descriptors of diff --git a/vendor/github.com/prometheus/procfs/proc_cgroup.go b/vendor/github.com/prometheus/procfs/proc_cgroup.go index cca03327c..daeed7f57 100644 --- a/vendor/github.com/prometheus/procfs/proc_cgroup.go +++ b/vendor/github.com/prometheus/procfs/proc_cgroup.go @@ -23,7 +23,7 @@ import ( "github.com/prometheus/procfs/internal/util" ) -// Cgroup models one line from /proc/[pid]/cgroup. Each Cgroup struct describes the the placement of a PID inside a +// Cgroup models one line from /proc/[pid]/cgroup. Each Cgroup struct describes the placement of a PID inside a // specific control hierarchy. The kernel has two cgroup APIs, v1 and v2. v1 has one hierarchy per available resource // controller, while v2 has one unified hierarchy shared by all controllers. Regardless of v1 or v2, all hierarchies // contain all running processes, so the question answerable with a Cgroup struct is 'where is this process in @@ -51,7 +51,7 @@ func parseCgroupString(cgroupStr string) (*Cgroup, error) { fields := strings.SplitN(cgroupStr, ":", 3) if len(fields) < 3 { - return nil, fmt.Errorf("at least 3 fields required, found %d fields in cgroup string: %s", len(fields), cgroupStr) + return nil, fmt.Errorf("%w: 3+ fields required, found %d fields in cgroup string: %s", ErrFileParse, len(fields), cgroupStr) } cgroup := &Cgroup{ @@ -60,7 +60,7 @@ func parseCgroupString(cgroupStr string) (*Cgroup, error) { } cgroup.HierarchyID, err = strconv.Atoi(fields[0]) if err != nil { - return nil, fmt.Errorf("failed to parse hierarchy ID") + return nil, fmt.Errorf("%w: hierarchy ID: %q", ErrFileParse, cgroup.HierarchyID) } if fields[1] != "" { ssNames := strings.Split(fields[1], ",") diff --git a/vendor/github.com/prometheus/procfs/proc_cgroups.go b/vendor/github.com/prometheus/procfs/proc_cgroups.go index 24d4dce9c..5dd493899 100644 --- a/vendor/github.com/prometheus/procfs/proc_cgroups.go +++ b/vendor/github.com/prometheus/procfs/proc_cgroups.go @@ -46,7 +46,7 @@ func parseCgroupSummaryString(CgroupSummaryStr string) (*CgroupSummary, error) { fields := strings.Fields(CgroupSummaryStr) // require at least 4 fields if len(fields) < 4 { - return nil, fmt.Errorf("at least 4 fields required, found %d fields in cgroup info string: %s", len(fields), CgroupSummaryStr) + return nil, fmt.Errorf("%w: 4+ fields required, found %d fields in cgroup info string: %s", ErrFileParse, len(fields), CgroupSummaryStr) } CgroupSummary := &CgroupSummary{ @@ -54,15 +54,15 @@ func parseCgroupSummaryString(CgroupSummaryStr string) (*CgroupSummary, error) { } CgroupSummary.Hierarchy, err = strconv.Atoi(fields[1]) if err != nil { - return nil, fmt.Errorf("failed to parse hierarchy ID") + return nil, fmt.Errorf("%w: Unable to parse hierarchy ID from %q", ErrFileParse, fields[1]) } CgroupSummary.Cgroups, err = strconv.Atoi(fields[2]) if err != nil { - return nil, fmt.Errorf("failed to parse Cgroup Num") + return nil, fmt.Errorf("%w: Unable to parse Cgroup Num from %q", ErrFileParse, fields[2]) } CgroupSummary.Enabled, err = strconv.Atoi(fields[3]) if err != nil { - return nil, fmt.Errorf("failed to parse Enabled") + return nil, fmt.Errorf("%w: Unable to parse Enabled from %q", ErrFileParse, fields[3]) } return CgroupSummary, nil } diff --git a/vendor/github.com/prometheus/procfs/proc_fdinfo.go b/vendor/github.com/prometheus/procfs/proc_fdinfo.go index 1bbdd4a8e..fa761b352 100644 --- a/vendor/github.com/prometheus/procfs/proc_fdinfo.go +++ b/vendor/github.com/prometheus/procfs/proc_fdinfo.go @@ -26,6 +26,7 @@ var ( rPos = regexp.MustCompile(`^pos:\s+(\d+)$`) rFlags = regexp.MustCompile(`^flags:\s+(\d+)$`) rMntID = regexp.MustCompile(`^mnt_id:\s+(\d+)$`) + rIno = regexp.MustCompile(`^ino:\s+(\d+)$`) rInotify = regexp.MustCompile(`^inotify`) rInotifyParts = regexp.MustCompile(`^inotify\s+wd:([0-9a-f]+)\s+ino:([0-9a-f]+)\s+sdev:([0-9a-f]+)(?:\s+mask:([0-9a-f]+))?`) ) @@ -40,6 +41,8 @@ type ProcFDInfo struct { Flags string // Mount point ID MntID string + // Inode number + Ino string // List of inotify lines (structured) in the fdinfo file (kernel 3.8+ only) InotifyInfos []InotifyInfo } @@ -51,7 +54,7 @@ func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) { return nil, err } - var text, pos, flags, mntid string + var text, pos, flags, mntid, ino string var inotify []InotifyInfo scanner := bufio.NewScanner(bytes.NewReader(data)) @@ -63,6 +66,8 @@ func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) { flags = rFlags.FindStringSubmatch(text)[1] } else if rMntID.MatchString(text) { mntid = rMntID.FindStringSubmatch(text)[1] + } else if rIno.MatchString(text) { + ino = rIno.FindStringSubmatch(text)[1] } else if rInotify.MatchString(text) { newInotify, err := parseInotifyInfo(text) if err != nil { @@ -77,6 +82,7 @@ func (p Proc) FDInfo(fd string) (*ProcFDInfo, error) { Pos: pos, Flags: flags, MntID: mntid, + Ino: ino, InotifyInfos: inotify, } @@ -111,7 +117,7 @@ func parseInotifyInfo(line string) (*InotifyInfo, error) { } return i, nil } - return nil, fmt.Errorf("invalid inode entry: %q", line) + return nil, fmt.Errorf("%w: invalid inode entry: %q", ErrFileParse, line) } // ProcFDInfos represents a list of ProcFDInfo structs. diff --git a/vendor/github.com/prometheus/procfs/proc_interrupts.go b/vendor/github.com/prometheus/procfs/proc_interrupts.go new file mode 100644 index 000000000..86b4b4524 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_interrupts.go @@ -0,0 +1,98 @@ +// Copyright 2022 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 procfs + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +// Interrupt represents a single interrupt line. +type Interrupt struct { + // Info is the type of interrupt. + Info string + // Devices is the name of the device that is located at that IRQ + Devices string + // Values is the number of interrupts per CPU. + Values []string +} + +// Interrupts models the content of /proc/interrupts. Key is the IRQ number. +// - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s2-proc-interrupts +// - https://raspberrypi.stackexchange.com/questions/105802/explanation-of-proc-interrupts-output +type Interrupts map[string]Interrupt + +// Interrupts creates a new instance from a given Proc instance. +func (p Proc) Interrupts() (Interrupts, error) { + data, err := util.ReadFileNoStat(p.path("interrupts")) + if err != nil { + return nil, err + } + return parseInterrupts(bytes.NewReader(data)) +} + +func parseInterrupts(r io.Reader) (Interrupts, error) { + var ( + interrupts = Interrupts{} + scanner = bufio.NewScanner(r) + ) + + if !scanner.Scan() { + return nil, errors.New("interrupts empty") + } + cpuNum := len(strings.Fields(scanner.Text())) // one header per cpu + + for scanner.Scan() { + parts := strings.Fields(scanner.Text()) + if len(parts) == 0 { // skip empty lines + continue + } + if len(parts) < 2 { + return nil, fmt.Errorf("%w: Not enough fields in interrupts (expected 2+ fields but got %d): %s", ErrFileParse, len(parts), parts) + } + intName := parts[0][:len(parts[0])-1] // remove trailing : + + if len(parts) == 2 { + interrupts[intName] = Interrupt{ + Info: "", + Devices: "", + Values: []string{ + parts[1], + }, + } + continue + } + + intr := Interrupt{ + Values: parts[1 : cpuNum+1], + } + + if _, err := strconv.Atoi(intName); err == nil { // numeral interrupt + intr.Info = parts[cpuNum+1] + intr.Devices = strings.Join(parts[cpuNum+2:], " ") + } else { + intr.Info = strings.Join(parts[cpuNum+1:], " ") + } + interrupts[intName] = intr + } + + return interrupts, scanner.Err() +} diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go index 7a1388185..c86d815d7 100644 --- a/vendor/github.com/prometheus/procfs/proc_limits.go +++ b/vendor/github.com/prometheus/procfs/proc_limits.go @@ -103,7 +103,7 @@ func (p Proc) Limits() (ProcLimits, error) { //fields := limitsMatch.Split(s.Text(), limitsFields) fields := limitsMatch.FindStringSubmatch(s.Text()) if len(fields) != limitsFields { - return ProcLimits{}, fmt.Errorf("couldn't parse %q line %q", f.Name(), s.Text()) + return ProcLimits{}, fmt.Errorf("%w: couldn't parse %q line %q", ErrFileParse, f.Name(), s.Text()) } switch fields[1] { @@ -154,7 +154,7 @@ func parseUint(s string) (uint64, error) { } i, err := strconv.ParseUint(s, 10, 64) if err != nil { - return 0, fmt.Errorf("couldn't parse value %q: %w", s, err) + return 0, fmt.Errorf("%s: couldn't parse value %q: %w", ErrFileParse, s, err) } return i, nil } diff --git a/vendor/github.com/prometheus/procfs/proc_maps.go b/vendor/github.com/prometheus/procfs/proc_maps.go index f1bcbf32b..7e75c286b 100644 --- a/vendor/github.com/prometheus/procfs/proc_maps.go +++ b/vendor/github.com/prometheus/procfs/proc_maps.go @@ -63,17 +63,17 @@ type ProcMap struct { // parseDevice parses the device token of a line and converts it to a dev_t // (mkdev) like structure. func parseDevice(s string) (uint64, error) { - toks := strings.Split(s, ":") - if len(toks) < 2 { - return 0, fmt.Errorf("unexpected number of fields") + i := strings.Index(s, ":") + if i == -1 { + return 0, fmt.Errorf("%w: expected separator `:` in %s", ErrFileParse, s) } - major, err := strconv.ParseUint(toks[0], 16, 0) + major, err := strconv.ParseUint(s[0:i], 16, 0) if err != nil { return 0, err } - minor, err := strconv.ParseUint(toks[1], 16, 0) + minor, err := strconv.ParseUint(s[i+1:], 16, 0) if err != nil { return 0, err } @@ -93,17 +93,17 @@ func parseAddress(s string) (uintptr, error) { // parseAddresses parses the start-end address. func parseAddresses(s string) (uintptr, uintptr, error) { - toks := strings.Split(s, "-") - if len(toks) < 2 { - return 0, 0, fmt.Errorf("invalid address") + idx := strings.Index(s, "-") + if idx == -1 { + return 0, 0, fmt.Errorf("%w: expected separator `-` in %s", ErrFileParse, s) } - saddr, err := parseAddress(toks[0]) + saddr, err := parseAddress(s[0:idx]) if err != nil { return 0, 0, err } - eaddr, err := parseAddress(toks[1]) + eaddr, err := parseAddress(s[idx+1:]) if err != nil { return 0, 0, err } @@ -114,7 +114,7 @@ func parseAddresses(s string) (uintptr, uintptr, error) { // parsePermissions parses a token and returns any that are set. func parsePermissions(s string) (*ProcMapPermissions, error) { if len(s) < 4 { - return nil, fmt.Errorf("invalid permissions token") + return nil, fmt.Errorf("%w: invalid permissions token", ErrFileParse) } perms := ProcMapPermissions{} @@ -141,7 +141,7 @@ func parsePermissions(s string) (*ProcMapPermissions, error) { func parseProcMap(text string) (*ProcMap, error) { fields := strings.Fields(text) if len(fields) < 5 { - return nil, fmt.Errorf("truncated procmap entry") + return nil, fmt.Errorf("%w: truncated procmap entry", ErrFileParse) } saddr, eaddr, err := parseAddresses(fields[0]) diff --git a/vendor/github.com/prometheus/procfs/proc_netstat.go b/vendor/github.com/prometheus/procfs/proc_netstat.go index 48b523819..8e3ff4d79 100644 --- a/vendor/github.com/prometheus/procfs/proc_netstat.go +++ b/vendor/github.com/prometheus/procfs/proc_netstat.go @@ -33,139 +33,140 @@ type ProcNetstat struct { } type TcpExt struct { // nolint:revive - SyncookiesSent float64 - SyncookiesRecv float64 - SyncookiesFailed float64 - EmbryonicRsts float64 - PruneCalled float64 - RcvPruned float64 - OfoPruned float64 - OutOfWindowIcmps float64 - LockDroppedIcmps float64 - ArpFilter float64 - TW float64 - TWRecycled float64 - TWKilled float64 - PAWSActive float64 - PAWSEstab float64 - DelayedACKs float64 - DelayedACKLocked float64 - DelayedACKLost float64 - ListenOverflows float64 - ListenDrops float64 - TCPHPHits float64 - TCPPureAcks float64 - TCPHPAcks float64 - TCPRenoRecovery float64 - TCPSackRecovery float64 - TCPSACKReneging float64 - TCPSACKReorder float64 - TCPRenoReorder float64 - TCPTSReorder float64 - TCPFullUndo float64 - TCPPartialUndo float64 - TCPDSACKUndo float64 - TCPLossUndo float64 - TCPLostRetransmit float64 - TCPRenoFailures float64 - TCPSackFailures float64 - TCPLossFailures float64 - TCPFastRetrans float64 - TCPSlowStartRetrans float64 - TCPTimeouts float64 - TCPLossProbes float64 - TCPLossProbeRecovery float64 - TCPRenoRecoveryFail float64 - TCPSackRecoveryFail float64 - TCPRcvCollapsed float64 - TCPDSACKOldSent float64 - TCPDSACKOfoSent float64 - TCPDSACKRecv float64 - TCPDSACKOfoRecv float64 - TCPAbortOnData float64 - TCPAbortOnClose float64 - TCPAbortOnMemory float64 - TCPAbortOnTimeout float64 - TCPAbortOnLinger float64 - TCPAbortFailed float64 - TCPMemoryPressures float64 - TCPMemoryPressuresChrono float64 - TCPSACKDiscard float64 - TCPDSACKIgnoredOld float64 - TCPDSACKIgnoredNoUndo float64 - TCPSpuriousRTOs float64 - TCPMD5NotFound float64 - TCPMD5Unexpected float64 - TCPMD5Failure float64 - TCPSackShifted float64 - TCPSackMerged float64 - TCPSackShiftFallback float64 - TCPBacklogDrop float64 - PFMemallocDrop float64 - TCPMinTTLDrop float64 - TCPDeferAcceptDrop float64 - IPReversePathFilter float64 - TCPTimeWaitOverflow float64 - TCPReqQFullDoCookies float64 - TCPReqQFullDrop float64 - TCPRetransFail float64 - TCPRcvCoalesce float64 - TCPOFOQueue float64 - TCPOFODrop float64 - TCPOFOMerge float64 - TCPChallengeACK float64 - TCPSYNChallenge float64 - TCPFastOpenActive float64 - TCPFastOpenActiveFail float64 - TCPFastOpenPassive float64 - TCPFastOpenPassiveFail float64 - TCPFastOpenListenOverflow float64 - TCPFastOpenCookieReqd float64 - TCPFastOpenBlackhole float64 - TCPSpuriousRtxHostQueues float64 - BusyPollRxPackets float64 - TCPAutoCorking float64 - TCPFromZeroWindowAdv float64 - TCPToZeroWindowAdv float64 - TCPWantZeroWindowAdv float64 - TCPSynRetrans float64 - TCPOrigDataSent float64 - TCPHystartTrainDetect float64 - TCPHystartTrainCwnd float64 - TCPHystartDelayDetect float64 - TCPHystartDelayCwnd float64 - TCPACKSkippedSynRecv float64 - TCPACKSkippedPAWS float64 - TCPACKSkippedSeq float64 - TCPACKSkippedFinWait2 float64 - TCPACKSkippedTimeWait float64 - TCPACKSkippedChallenge float64 - TCPWinProbe float64 - TCPKeepAlive float64 - TCPMTUPFail float64 - TCPMTUPSuccess float64 - TCPWqueueTooBig float64 + SyncookiesSent *float64 + SyncookiesRecv *float64 + SyncookiesFailed *float64 + EmbryonicRsts *float64 + PruneCalled *float64 + RcvPruned *float64 + OfoPruned *float64 + OutOfWindowIcmps *float64 + LockDroppedIcmps *float64 + ArpFilter *float64 + TW *float64 + TWRecycled *float64 + TWKilled *float64 + PAWSActive *float64 + PAWSEstab *float64 + DelayedACKs *float64 + DelayedACKLocked *float64 + DelayedACKLost *float64 + ListenOverflows *float64 + ListenDrops *float64 + TCPHPHits *float64 + TCPPureAcks *float64 + TCPHPAcks *float64 + TCPRenoRecovery *float64 + TCPSackRecovery *float64 + TCPSACKReneging *float64 + TCPSACKReorder *float64 + TCPRenoReorder *float64 + TCPTSReorder *float64 + TCPFullUndo *float64 + TCPPartialUndo *float64 + TCPDSACKUndo *float64 + TCPLossUndo *float64 + TCPLostRetransmit *float64 + TCPRenoFailures *float64 + TCPSackFailures *float64 + TCPLossFailures *float64 + TCPFastRetrans *float64 + TCPSlowStartRetrans *float64 + TCPTimeouts *float64 + TCPLossProbes *float64 + TCPLossProbeRecovery *float64 + TCPRenoRecoveryFail *float64 + TCPSackRecoveryFail *float64 + TCPRcvCollapsed *float64 + TCPDSACKOldSent *float64 + TCPDSACKOfoSent *float64 + TCPDSACKRecv *float64 + TCPDSACKOfoRecv *float64 + TCPAbortOnData *float64 + TCPAbortOnClose *float64 + TCPAbortOnMemory *float64 + TCPAbortOnTimeout *float64 + TCPAbortOnLinger *float64 + TCPAbortFailed *float64 + TCPMemoryPressures *float64 + TCPMemoryPressuresChrono *float64 + TCPSACKDiscard *float64 + TCPDSACKIgnoredOld *float64 + TCPDSACKIgnoredNoUndo *float64 + TCPSpuriousRTOs *float64 + TCPMD5NotFound *float64 + TCPMD5Unexpected *float64 + TCPMD5Failure *float64 + TCPSackShifted *float64 + TCPSackMerged *float64 + TCPSackShiftFallback *float64 + TCPBacklogDrop *float64 + PFMemallocDrop *float64 + TCPMinTTLDrop *float64 + TCPDeferAcceptDrop *float64 + IPReversePathFilter *float64 + TCPTimeWaitOverflow *float64 + TCPReqQFullDoCookies *float64 + TCPReqQFullDrop *float64 + TCPRetransFail *float64 + TCPRcvCoalesce *float64 + TCPRcvQDrop *float64 + TCPOFOQueue *float64 + TCPOFODrop *float64 + TCPOFOMerge *float64 + TCPChallengeACK *float64 + TCPSYNChallenge *float64 + TCPFastOpenActive *float64 + TCPFastOpenActiveFail *float64 + TCPFastOpenPassive *float64 + TCPFastOpenPassiveFail *float64 + TCPFastOpenListenOverflow *float64 + TCPFastOpenCookieReqd *float64 + TCPFastOpenBlackhole *float64 + TCPSpuriousRtxHostQueues *float64 + BusyPollRxPackets *float64 + TCPAutoCorking *float64 + TCPFromZeroWindowAdv *float64 + TCPToZeroWindowAdv *float64 + TCPWantZeroWindowAdv *float64 + TCPSynRetrans *float64 + TCPOrigDataSent *float64 + TCPHystartTrainDetect *float64 + TCPHystartTrainCwnd *float64 + TCPHystartDelayDetect *float64 + TCPHystartDelayCwnd *float64 + TCPACKSkippedSynRecv *float64 + TCPACKSkippedPAWS *float64 + TCPACKSkippedSeq *float64 + TCPACKSkippedFinWait2 *float64 + TCPACKSkippedTimeWait *float64 + TCPACKSkippedChallenge *float64 + TCPWinProbe *float64 + TCPKeepAlive *float64 + TCPMTUPFail *float64 + TCPMTUPSuccess *float64 + TCPWqueueTooBig *float64 } type IpExt struct { // nolint:revive - InNoRoutes float64 - InTruncatedPkts float64 - InMcastPkts float64 - OutMcastPkts float64 - InBcastPkts float64 - OutBcastPkts float64 - InOctets float64 - OutOctets float64 - InMcastOctets float64 - OutMcastOctets float64 - InBcastOctets float64 - OutBcastOctets float64 - InCsumErrors float64 - InNoECTPkts float64 - InECT1Pkts float64 - InECT0Pkts float64 - InCEPkts float64 - ReasmOverlaps float64 + InNoRoutes *float64 + InTruncatedPkts *float64 + InMcastPkts *float64 + OutMcastPkts *float64 + InBcastPkts *float64 + OutBcastPkts *float64 + InOctets *float64 + OutOctets *float64 + InMcastOctets *float64 + OutMcastOctets *float64 + InBcastOctets *float64 + OutBcastOctets *float64 + InCsumErrors *float64 + InNoECTPkts *float64 + InECT1Pkts *float64 + InECT0Pkts *float64 + InCEPkts *float64 + ReasmOverlaps *float64 } func (p Proc) Netstat() (ProcNetstat, error) { @@ -174,14 +175,14 @@ func (p Proc) Netstat() (ProcNetstat, error) { if err != nil { return ProcNetstat{PID: p.PID}, err } - procNetstat, err := parseNetstat(bytes.NewReader(data), filename) + procNetstat, err := parseProcNetstat(bytes.NewReader(data), filename) procNetstat.PID = p.PID return procNetstat, err } -// parseNetstat parses the metrics from proc//net/netstat file +// parseProcNetstat parses the metrics from proc//net/netstat file // and returns a ProcNetstat structure. -func parseNetstat(r io.Reader, fileName string) (ProcNetstat, error) { +func parseProcNetstat(r io.Reader, fileName string) (ProcNetstat, error) { var ( scanner = bufio.NewScanner(r) procNetstat = ProcNetstat{} @@ -194,8 +195,8 @@ func parseNetstat(r io.Reader, fileName string) (ProcNetstat, error) { // Remove trailing :. protocol := strings.TrimSuffix(nameParts[0], ":") if len(nameParts) != len(valueParts) { - return procNetstat, fmt.Errorf("mismatch field count mismatch in %s: %s", - fileName, protocol) + return procNetstat, fmt.Errorf("%w: mismatch field count mismatch in %s: %s", + ErrFileParse, fileName, protocol) } for i := 1; i < len(nameParts); i++ { value, err := strconv.ParseFloat(valueParts[i], 64) @@ -208,230 +209,232 @@ func parseNetstat(r io.Reader, fileName string) (ProcNetstat, error) { case "TcpExt": switch key { case "SyncookiesSent": - procNetstat.TcpExt.SyncookiesSent = value + procNetstat.TcpExt.SyncookiesSent = &value case "SyncookiesRecv": - procNetstat.TcpExt.SyncookiesRecv = value + procNetstat.TcpExt.SyncookiesRecv = &value case "SyncookiesFailed": - procNetstat.TcpExt.SyncookiesFailed = value + procNetstat.TcpExt.SyncookiesFailed = &value case "EmbryonicRsts": - procNetstat.TcpExt.EmbryonicRsts = value + procNetstat.TcpExt.EmbryonicRsts = &value case "PruneCalled": - procNetstat.TcpExt.PruneCalled = value + procNetstat.TcpExt.PruneCalled = &value case "RcvPruned": - procNetstat.TcpExt.RcvPruned = value + procNetstat.TcpExt.RcvPruned = &value case "OfoPruned": - procNetstat.TcpExt.OfoPruned = value + procNetstat.TcpExt.OfoPruned = &value case "OutOfWindowIcmps": - procNetstat.TcpExt.OutOfWindowIcmps = value + procNetstat.TcpExt.OutOfWindowIcmps = &value case "LockDroppedIcmps": - procNetstat.TcpExt.LockDroppedIcmps = value + procNetstat.TcpExt.LockDroppedIcmps = &value case "ArpFilter": - procNetstat.TcpExt.ArpFilter = value + procNetstat.TcpExt.ArpFilter = &value case "TW": - procNetstat.TcpExt.TW = value + procNetstat.TcpExt.TW = &value case "TWRecycled": - procNetstat.TcpExt.TWRecycled = value + procNetstat.TcpExt.TWRecycled = &value case "TWKilled": - procNetstat.TcpExt.TWKilled = value + procNetstat.TcpExt.TWKilled = &value case "PAWSActive": - procNetstat.TcpExt.PAWSActive = value + procNetstat.TcpExt.PAWSActive = &value case "PAWSEstab": - procNetstat.TcpExt.PAWSEstab = value + procNetstat.TcpExt.PAWSEstab = &value case "DelayedACKs": - procNetstat.TcpExt.DelayedACKs = value + procNetstat.TcpExt.DelayedACKs = &value case "DelayedACKLocked": - procNetstat.TcpExt.DelayedACKLocked = value + procNetstat.TcpExt.DelayedACKLocked = &value case "DelayedACKLost": - procNetstat.TcpExt.DelayedACKLost = value + procNetstat.TcpExt.DelayedACKLost = &value case "ListenOverflows": - procNetstat.TcpExt.ListenOverflows = value + procNetstat.TcpExt.ListenOverflows = &value case "ListenDrops": - procNetstat.TcpExt.ListenDrops = value + procNetstat.TcpExt.ListenDrops = &value case "TCPHPHits": - procNetstat.TcpExt.TCPHPHits = value + procNetstat.TcpExt.TCPHPHits = &value case "TCPPureAcks": - procNetstat.TcpExt.TCPPureAcks = value + procNetstat.TcpExt.TCPPureAcks = &value case "TCPHPAcks": - procNetstat.TcpExt.TCPHPAcks = value + procNetstat.TcpExt.TCPHPAcks = &value case "TCPRenoRecovery": - procNetstat.TcpExt.TCPRenoRecovery = value + procNetstat.TcpExt.TCPRenoRecovery = &value case "TCPSackRecovery": - procNetstat.TcpExt.TCPSackRecovery = value + procNetstat.TcpExt.TCPSackRecovery = &value case "TCPSACKReneging": - procNetstat.TcpExt.TCPSACKReneging = value + procNetstat.TcpExt.TCPSACKReneging = &value case "TCPSACKReorder": - procNetstat.TcpExt.TCPSACKReorder = value + procNetstat.TcpExt.TCPSACKReorder = &value case "TCPRenoReorder": - procNetstat.TcpExt.TCPRenoReorder = value + procNetstat.TcpExt.TCPRenoReorder = &value case "TCPTSReorder": - procNetstat.TcpExt.TCPTSReorder = value + procNetstat.TcpExt.TCPTSReorder = &value case "TCPFullUndo": - procNetstat.TcpExt.TCPFullUndo = value + procNetstat.TcpExt.TCPFullUndo = &value case "TCPPartialUndo": - procNetstat.TcpExt.TCPPartialUndo = value + procNetstat.TcpExt.TCPPartialUndo = &value case "TCPDSACKUndo": - procNetstat.TcpExt.TCPDSACKUndo = value + procNetstat.TcpExt.TCPDSACKUndo = &value case "TCPLossUndo": - procNetstat.TcpExt.TCPLossUndo = value + procNetstat.TcpExt.TCPLossUndo = &value case "TCPLostRetransmit": - procNetstat.TcpExt.TCPLostRetransmit = value + procNetstat.TcpExt.TCPLostRetransmit = &value case "TCPRenoFailures": - procNetstat.TcpExt.TCPRenoFailures = value + procNetstat.TcpExt.TCPRenoFailures = &value case "TCPSackFailures": - procNetstat.TcpExt.TCPSackFailures = value + procNetstat.TcpExt.TCPSackFailures = &value case "TCPLossFailures": - procNetstat.TcpExt.TCPLossFailures = value + procNetstat.TcpExt.TCPLossFailures = &value case "TCPFastRetrans": - procNetstat.TcpExt.TCPFastRetrans = value + procNetstat.TcpExt.TCPFastRetrans = &value case "TCPSlowStartRetrans": - procNetstat.TcpExt.TCPSlowStartRetrans = value + procNetstat.TcpExt.TCPSlowStartRetrans = &value case "TCPTimeouts": - procNetstat.TcpExt.TCPTimeouts = value + procNetstat.TcpExt.TCPTimeouts = &value case "TCPLossProbes": - procNetstat.TcpExt.TCPLossProbes = value + procNetstat.TcpExt.TCPLossProbes = &value case "TCPLossProbeRecovery": - procNetstat.TcpExt.TCPLossProbeRecovery = value + procNetstat.TcpExt.TCPLossProbeRecovery = &value case "TCPRenoRecoveryFail": - procNetstat.TcpExt.TCPRenoRecoveryFail = value + procNetstat.TcpExt.TCPRenoRecoveryFail = &value case "TCPSackRecoveryFail": - procNetstat.TcpExt.TCPSackRecoveryFail = value + procNetstat.TcpExt.TCPSackRecoveryFail = &value case "TCPRcvCollapsed": - procNetstat.TcpExt.TCPRcvCollapsed = value + procNetstat.TcpExt.TCPRcvCollapsed = &value case "TCPDSACKOldSent": - procNetstat.TcpExt.TCPDSACKOldSent = value + procNetstat.TcpExt.TCPDSACKOldSent = &value case "TCPDSACKOfoSent": - procNetstat.TcpExt.TCPDSACKOfoSent = value + procNetstat.TcpExt.TCPDSACKOfoSent = &value case "TCPDSACKRecv": - procNetstat.TcpExt.TCPDSACKRecv = value + procNetstat.TcpExt.TCPDSACKRecv = &value case "TCPDSACKOfoRecv": - procNetstat.TcpExt.TCPDSACKOfoRecv = value + procNetstat.TcpExt.TCPDSACKOfoRecv = &value case "TCPAbortOnData": - procNetstat.TcpExt.TCPAbortOnData = value + procNetstat.TcpExt.TCPAbortOnData = &value case "TCPAbortOnClose": - procNetstat.TcpExt.TCPAbortOnClose = value + procNetstat.TcpExt.TCPAbortOnClose = &value case "TCPDeferAcceptDrop": - procNetstat.TcpExt.TCPDeferAcceptDrop = value + procNetstat.TcpExt.TCPDeferAcceptDrop = &value case "IPReversePathFilter": - procNetstat.TcpExt.IPReversePathFilter = value + procNetstat.TcpExt.IPReversePathFilter = &value case "TCPTimeWaitOverflow": - procNetstat.TcpExt.TCPTimeWaitOverflow = value + procNetstat.TcpExt.TCPTimeWaitOverflow = &value case "TCPReqQFullDoCookies": - procNetstat.TcpExt.TCPReqQFullDoCookies = value + procNetstat.TcpExt.TCPReqQFullDoCookies = &value case "TCPReqQFullDrop": - procNetstat.TcpExt.TCPReqQFullDrop = value + procNetstat.TcpExt.TCPReqQFullDrop = &value case "TCPRetransFail": - procNetstat.TcpExt.TCPRetransFail = value + procNetstat.TcpExt.TCPRetransFail = &value case "TCPRcvCoalesce": - procNetstat.TcpExt.TCPRcvCoalesce = value + procNetstat.TcpExt.TCPRcvCoalesce = &value + case "TCPRcvQDrop": + procNetstat.TcpExt.TCPRcvQDrop = &value case "TCPOFOQueue": - procNetstat.TcpExt.TCPOFOQueue = value + procNetstat.TcpExt.TCPOFOQueue = &value case "TCPOFODrop": - procNetstat.TcpExt.TCPOFODrop = value + procNetstat.TcpExt.TCPOFODrop = &value case "TCPOFOMerge": - procNetstat.TcpExt.TCPOFOMerge = value + procNetstat.TcpExt.TCPOFOMerge = &value case "TCPChallengeACK": - procNetstat.TcpExt.TCPChallengeACK = value + procNetstat.TcpExt.TCPChallengeACK = &value case "TCPSYNChallenge": - procNetstat.TcpExt.TCPSYNChallenge = value + procNetstat.TcpExt.TCPSYNChallenge = &value case "TCPFastOpenActive": - procNetstat.TcpExt.TCPFastOpenActive = value + procNetstat.TcpExt.TCPFastOpenActive = &value case "TCPFastOpenActiveFail": - procNetstat.TcpExt.TCPFastOpenActiveFail = value + procNetstat.TcpExt.TCPFastOpenActiveFail = &value case "TCPFastOpenPassive": - procNetstat.TcpExt.TCPFastOpenPassive = value + procNetstat.TcpExt.TCPFastOpenPassive = &value case "TCPFastOpenPassiveFail": - procNetstat.TcpExt.TCPFastOpenPassiveFail = value + procNetstat.TcpExt.TCPFastOpenPassiveFail = &value case "TCPFastOpenListenOverflow": - procNetstat.TcpExt.TCPFastOpenListenOverflow = value + procNetstat.TcpExt.TCPFastOpenListenOverflow = &value case "TCPFastOpenCookieReqd": - procNetstat.TcpExt.TCPFastOpenCookieReqd = value + procNetstat.TcpExt.TCPFastOpenCookieReqd = &value case "TCPFastOpenBlackhole": - procNetstat.TcpExt.TCPFastOpenBlackhole = value + procNetstat.TcpExt.TCPFastOpenBlackhole = &value case "TCPSpuriousRtxHostQueues": - procNetstat.TcpExt.TCPSpuriousRtxHostQueues = value + procNetstat.TcpExt.TCPSpuriousRtxHostQueues = &value case "BusyPollRxPackets": - procNetstat.TcpExt.BusyPollRxPackets = value + procNetstat.TcpExt.BusyPollRxPackets = &value case "TCPAutoCorking": - procNetstat.TcpExt.TCPAutoCorking = value + procNetstat.TcpExt.TCPAutoCorking = &value case "TCPFromZeroWindowAdv": - procNetstat.TcpExt.TCPFromZeroWindowAdv = value + procNetstat.TcpExt.TCPFromZeroWindowAdv = &value case "TCPToZeroWindowAdv": - procNetstat.TcpExt.TCPToZeroWindowAdv = value + procNetstat.TcpExt.TCPToZeroWindowAdv = &value case "TCPWantZeroWindowAdv": - procNetstat.TcpExt.TCPWantZeroWindowAdv = value + procNetstat.TcpExt.TCPWantZeroWindowAdv = &value case "TCPSynRetrans": - procNetstat.TcpExt.TCPSynRetrans = value + procNetstat.TcpExt.TCPSynRetrans = &value case "TCPOrigDataSent": - procNetstat.TcpExt.TCPOrigDataSent = value + procNetstat.TcpExt.TCPOrigDataSent = &value case "TCPHystartTrainDetect": - procNetstat.TcpExt.TCPHystartTrainDetect = value + procNetstat.TcpExt.TCPHystartTrainDetect = &value case "TCPHystartTrainCwnd": - procNetstat.TcpExt.TCPHystartTrainCwnd = value + procNetstat.TcpExt.TCPHystartTrainCwnd = &value case "TCPHystartDelayDetect": - procNetstat.TcpExt.TCPHystartDelayDetect = value + procNetstat.TcpExt.TCPHystartDelayDetect = &value case "TCPHystartDelayCwnd": - procNetstat.TcpExt.TCPHystartDelayCwnd = value + procNetstat.TcpExt.TCPHystartDelayCwnd = &value case "TCPACKSkippedSynRecv": - procNetstat.TcpExt.TCPACKSkippedSynRecv = value + procNetstat.TcpExt.TCPACKSkippedSynRecv = &value case "TCPACKSkippedPAWS": - procNetstat.TcpExt.TCPACKSkippedPAWS = value + procNetstat.TcpExt.TCPACKSkippedPAWS = &value case "TCPACKSkippedSeq": - procNetstat.TcpExt.TCPACKSkippedSeq = value + procNetstat.TcpExt.TCPACKSkippedSeq = &value case "TCPACKSkippedFinWait2": - procNetstat.TcpExt.TCPACKSkippedFinWait2 = value + procNetstat.TcpExt.TCPACKSkippedFinWait2 = &value case "TCPACKSkippedTimeWait": - procNetstat.TcpExt.TCPACKSkippedTimeWait = value + procNetstat.TcpExt.TCPACKSkippedTimeWait = &value case "TCPACKSkippedChallenge": - procNetstat.TcpExt.TCPACKSkippedChallenge = value + procNetstat.TcpExt.TCPACKSkippedChallenge = &value case "TCPWinProbe": - procNetstat.TcpExt.TCPWinProbe = value + procNetstat.TcpExt.TCPWinProbe = &value case "TCPKeepAlive": - procNetstat.TcpExt.TCPKeepAlive = value + procNetstat.TcpExt.TCPKeepAlive = &value case "TCPMTUPFail": - procNetstat.TcpExt.TCPMTUPFail = value + procNetstat.TcpExt.TCPMTUPFail = &value case "TCPMTUPSuccess": - procNetstat.TcpExt.TCPMTUPSuccess = value + procNetstat.TcpExt.TCPMTUPSuccess = &value case "TCPWqueueTooBig": - procNetstat.TcpExt.TCPWqueueTooBig = value + procNetstat.TcpExt.TCPWqueueTooBig = &value } case "IpExt": switch key { case "InNoRoutes": - procNetstat.IpExt.InNoRoutes = value + procNetstat.IpExt.InNoRoutes = &value case "InTruncatedPkts": - procNetstat.IpExt.InTruncatedPkts = value + procNetstat.IpExt.InTruncatedPkts = &value case "InMcastPkts": - procNetstat.IpExt.InMcastPkts = value + procNetstat.IpExt.InMcastPkts = &value case "OutMcastPkts": - procNetstat.IpExt.OutMcastPkts = value + procNetstat.IpExt.OutMcastPkts = &value case "InBcastPkts": - procNetstat.IpExt.InBcastPkts = value + procNetstat.IpExt.InBcastPkts = &value case "OutBcastPkts": - procNetstat.IpExt.OutBcastPkts = value + procNetstat.IpExt.OutBcastPkts = &value case "InOctets": - procNetstat.IpExt.InOctets = value + procNetstat.IpExt.InOctets = &value case "OutOctets": - procNetstat.IpExt.OutOctets = value + procNetstat.IpExt.OutOctets = &value case "InMcastOctets": - procNetstat.IpExt.InMcastOctets = value + procNetstat.IpExt.InMcastOctets = &value case "OutMcastOctets": - procNetstat.IpExt.OutMcastOctets = value + procNetstat.IpExt.OutMcastOctets = &value case "InBcastOctets": - procNetstat.IpExt.InBcastOctets = value + procNetstat.IpExt.InBcastOctets = &value case "OutBcastOctets": - procNetstat.IpExt.OutBcastOctets = value + procNetstat.IpExt.OutBcastOctets = &value case "InCsumErrors": - procNetstat.IpExt.InCsumErrors = value + procNetstat.IpExt.InCsumErrors = &value case "InNoECTPkts": - procNetstat.IpExt.InNoECTPkts = value + procNetstat.IpExt.InNoECTPkts = &value case "InECT1Pkts": - procNetstat.IpExt.InECT1Pkts = value + procNetstat.IpExt.InECT1Pkts = &value case "InECT0Pkts": - procNetstat.IpExt.InECT0Pkts = value + procNetstat.IpExt.InECT0Pkts = &value case "InCEPkts": - procNetstat.IpExt.InCEPkts = value + procNetstat.IpExt.InCEPkts = &value case "ReasmOverlaps": - procNetstat.IpExt.ReasmOverlaps = value + procNetstat.IpExt.ReasmOverlaps = &value } } } diff --git a/vendor/github.com/prometheus/procfs/proc_ns.go b/vendor/github.com/prometheus/procfs/proc_ns.go index 391b4cbd1..c22666750 100644 --- a/vendor/github.com/prometheus/procfs/proc_ns.go +++ b/vendor/github.com/prometheus/procfs/proc_ns.go @@ -40,7 +40,7 @@ func (p Proc) Namespaces() (Namespaces, error) { names, err := d.Readdirnames(-1) if err != nil { - return nil, fmt.Errorf("failed to read contents of ns dir: %w", err) + return nil, fmt.Errorf("%s: failed to read contents of ns dir: %w", ErrFileRead, err) } ns := make(Namespaces, len(names)) @@ -52,13 +52,13 @@ func (p Proc) Namespaces() (Namespaces, error) { fields := strings.SplitN(target, ":", 2) if len(fields) != 2 { - return nil, fmt.Errorf("failed to parse namespace type and inode from %q", target) + return nil, fmt.Errorf("%w: namespace type and inode from %q", ErrFileParse, target) } typ := fields[0] inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32) if err != nil { - return nil, fmt.Errorf("failed to parse inode from %q: %w", fields[1], err) + return nil, fmt.Errorf("%s: inode from %q: %w", ErrFileParse, fields[1], err) } ns[name] = Namespace{typ, uint32(inode)} diff --git a/vendor/github.com/prometheus/procfs/proc_psi.go b/vendor/github.com/prometheus/procfs/proc_psi.go index a68fe1529..fe9dbb425 100644 --- a/vendor/github.com/prometheus/procfs/proc_psi.go +++ b/vendor/github.com/prometheus/procfs/proc_psi.go @@ -61,14 +61,14 @@ type PSIStats struct { func (fs FS) PSIStatsForResource(resource string) (PSIStats, error) { data, err := util.ReadFileNoStat(fs.proc.Path(fmt.Sprintf("%s/%s", "pressure", resource))) if err != nil { - return PSIStats{}, fmt.Errorf("psi_stats: unavailable for %q: %w", resource, err) + return PSIStats{}, fmt.Errorf("%s: psi_stats: unavailable for %q: %w", ErrFileRead, resource, err) } - return parsePSIStats(resource, bytes.NewReader(data)) + return parsePSIStats(bytes.NewReader(data)) } // parsePSIStats parses the specified file for pressure stall information. -func parsePSIStats(resource string, r io.Reader) (PSIStats, error) { +func parsePSIStats(r io.Reader) (PSIStats, error) { psiStats := PSIStats{} scanner := bufio.NewScanner(r) diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go index 0e97d9957..ad8785a40 100644 --- a/vendor/github.com/prometheus/procfs/proc_smaps.go +++ b/vendor/github.com/prometheus/procfs/proc_smaps.go @@ -135,12 +135,12 @@ func (s *ProcSMapsRollup) parseLine(line string) error { } vBytes := vKBytes * 1024 - s.addValue(k, v, vKBytes, vBytes) + s.addValue(k, vBytes) return nil } -func (s *ProcSMapsRollup) addValue(k string, vString string, vUint uint64, vUintBytes uint64) { +func (s *ProcSMapsRollup) addValue(k string, vUintBytes uint64) { switch k { case "Rss": s.Rss += vUintBytes diff --git a/vendor/github.com/prometheus/procfs/proc_snmp.go b/vendor/github.com/prometheus/procfs/proc_snmp.go index ae191896c..b9d2cf642 100644 --- a/vendor/github.com/prometheus/procfs/proc_snmp.go +++ b/vendor/github.com/prometheus/procfs/proc_snmp.go @@ -37,100 +37,100 @@ type ProcSnmp struct { } type Ip struct { // nolint:revive - Forwarding float64 - DefaultTTL float64 - InReceives float64 - InHdrErrors float64 - InAddrErrors float64 - ForwDatagrams float64 - InUnknownProtos float64 - InDiscards float64 - InDelivers float64 - OutRequests float64 - OutDiscards float64 - OutNoRoutes float64 - ReasmTimeout float64 - ReasmReqds float64 - ReasmOKs float64 - ReasmFails float64 - FragOKs float64 - FragFails float64 - FragCreates float64 + Forwarding *float64 + DefaultTTL *float64 + InReceives *float64 + InHdrErrors *float64 + InAddrErrors *float64 + ForwDatagrams *float64 + InUnknownProtos *float64 + InDiscards *float64 + InDelivers *float64 + OutRequests *float64 + OutDiscards *float64 + OutNoRoutes *float64 + ReasmTimeout *float64 + ReasmReqds *float64 + ReasmOKs *float64 + ReasmFails *float64 + FragOKs *float64 + FragFails *float64 + FragCreates *float64 } -type Icmp struct { - InMsgs float64 - InErrors float64 - InCsumErrors float64 - InDestUnreachs float64 - InTimeExcds float64 - InParmProbs float64 - InSrcQuenchs float64 - InRedirects float64 - InEchos float64 - InEchoReps float64 - InTimestamps float64 - InTimestampReps float64 - InAddrMasks float64 - InAddrMaskReps float64 - OutMsgs float64 - OutErrors float64 - OutDestUnreachs float64 - OutTimeExcds float64 - OutParmProbs float64 - OutSrcQuenchs float64 - OutRedirects float64 - OutEchos float64 - OutEchoReps float64 - OutTimestamps float64 - OutTimestampReps float64 - OutAddrMasks float64 - OutAddrMaskReps float64 +type Icmp struct { // nolint:revive + InMsgs *float64 + InErrors *float64 + InCsumErrors *float64 + InDestUnreachs *float64 + InTimeExcds *float64 + InParmProbs *float64 + InSrcQuenchs *float64 + InRedirects *float64 + InEchos *float64 + InEchoReps *float64 + InTimestamps *float64 + InTimestampReps *float64 + InAddrMasks *float64 + InAddrMaskReps *float64 + OutMsgs *float64 + OutErrors *float64 + OutDestUnreachs *float64 + OutTimeExcds *float64 + OutParmProbs *float64 + OutSrcQuenchs *float64 + OutRedirects *float64 + OutEchos *float64 + OutEchoReps *float64 + OutTimestamps *float64 + OutTimestampReps *float64 + OutAddrMasks *float64 + OutAddrMaskReps *float64 } type IcmpMsg struct { - InType3 float64 - OutType3 float64 + InType3 *float64 + OutType3 *float64 } type Tcp struct { // nolint:revive - RtoAlgorithm float64 - RtoMin float64 - RtoMax float64 - MaxConn float64 - ActiveOpens float64 - PassiveOpens float64 - AttemptFails float64 - EstabResets float64 - CurrEstab float64 - InSegs float64 - OutSegs float64 - RetransSegs float64 - InErrs float64 - OutRsts float64 - InCsumErrors float64 + RtoAlgorithm *float64 + RtoMin *float64 + RtoMax *float64 + MaxConn *float64 + ActiveOpens *float64 + PassiveOpens *float64 + AttemptFails *float64 + EstabResets *float64 + CurrEstab *float64 + InSegs *float64 + OutSegs *float64 + RetransSegs *float64 + InErrs *float64 + OutRsts *float64 + InCsumErrors *float64 } type Udp struct { // nolint:revive - InDatagrams float64 - NoPorts float64 - InErrors float64 - OutDatagrams float64 - RcvbufErrors float64 - SndbufErrors float64 - InCsumErrors float64 - IgnoredMulti float64 + InDatagrams *float64 + NoPorts *float64 + InErrors *float64 + OutDatagrams *float64 + RcvbufErrors *float64 + SndbufErrors *float64 + InCsumErrors *float64 + IgnoredMulti *float64 } type UdpLite struct { // nolint:revive - InDatagrams float64 - NoPorts float64 - InErrors float64 - OutDatagrams float64 - RcvbufErrors float64 - SndbufErrors float64 - InCsumErrors float64 - IgnoredMulti float64 + InDatagrams *float64 + NoPorts *float64 + InErrors *float64 + OutDatagrams *float64 + RcvbufErrors *float64 + SndbufErrors *float64 + InCsumErrors *float64 + IgnoredMulti *float64 } func (p Proc) Snmp() (ProcSnmp, error) { @@ -159,8 +159,8 @@ func parseSnmp(r io.Reader, fileName string) (ProcSnmp, error) { // Remove trailing :. protocol := strings.TrimSuffix(nameParts[0], ":") if len(nameParts) != len(valueParts) { - return procSnmp, fmt.Errorf("mismatch field count mismatch in %s: %s", - fileName, protocol) + return procSnmp, fmt.Errorf("%w: mismatch field count mismatch in %s: %s", + ErrFileParse, fileName, protocol) } for i := 1; i < len(nameParts); i++ { value, err := strconv.ParseFloat(valueParts[i], 64) @@ -173,178 +173,178 @@ func parseSnmp(r io.Reader, fileName string) (ProcSnmp, error) { case "Ip": switch key { case "Forwarding": - procSnmp.Ip.Forwarding = value + procSnmp.Ip.Forwarding = &value case "DefaultTTL": - procSnmp.Ip.DefaultTTL = value + procSnmp.Ip.DefaultTTL = &value case "InReceives": - procSnmp.Ip.InReceives = value + procSnmp.Ip.InReceives = &value case "InHdrErrors": - procSnmp.Ip.InHdrErrors = value + procSnmp.Ip.InHdrErrors = &value case "InAddrErrors": - procSnmp.Ip.InAddrErrors = value + procSnmp.Ip.InAddrErrors = &value case "ForwDatagrams": - procSnmp.Ip.ForwDatagrams = value + procSnmp.Ip.ForwDatagrams = &value case "InUnknownProtos": - procSnmp.Ip.InUnknownProtos = value + procSnmp.Ip.InUnknownProtos = &value case "InDiscards": - procSnmp.Ip.InDiscards = value + procSnmp.Ip.InDiscards = &value case "InDelivers": - procSnmp.Ip.InDelivers = value + procSnmp.Ip.InDelivers = &value case "OutRequests": - procSnmp.Ip.OutRequests = value + procSnmp.Ip.OutRequests = &value case "OutDiscards": - procSnmp.Ip.OutDiscards = value + procSnmp.Ip.OutDiscards = &value case "OutNoRoutes": - procSnmp.Ip.OutNoRoutes = value + procSnmp.Ip.OutNoRoutes = &value case "ReasmTimeout": - procSnmp.Ip.ReasmTimeout = value + procSnmp.Ip.ReasmTimeout = &value case "ReasmReqds": - procSnmp.Ip.ReasmReqds = value + procSnmp.Ip.ReasmReqds = &value case "ReasmOKs": - procSnmp.Ip.ReasmOKs = value + procSnmp.Ip.ReasmOKs = &value case "ReasmFails": - procSnmp.Ip.ReasmFails = value + procSnmp.Ip.ReasmFails = &value case "FragOKs": - procSnmp.Ip.FragOKs = value + procSnmp.Ip.FragOKs = &value case "FragFails": - procSnmp.Ip.FragFails = value + procSnmp.Ip.FragFails = &value case "FragCreates": - procSnmp.Ip.FragCreates = value + procSnmp.Ip.FragCreates = &value } case "Icmp": switch key { case "InMsgs": - procSnmp.Icmp.InMsgs = value + procSnmp.Icmp.InMsgs = &value case "InErrors": - procSnmp.Icmp.InErrors = value + procSnmp.Icmp.InErrors = &value case "InCsumErrors": - procSnmp.Icmp.InCsumErrors = value + procSnmp.Icmp.InCsumErrors = &value case "InDestUnreachs": - procSnmp.Icmp.InDestUnreachs = value + procSnmp.Icmp.InDestUnreachs = &value case "InTimeExcds": - procSnmp.Icmp.InTimeExcds = value + procSnmp.Icmp.InTimeExcds = &value case "InParmProbs": - procSnmp.Icmp.InParmProbs = value + procSnmp.Icmp.InParmProbs = &value case "InSrcQuenchs": - procSnmp.Icmp.InSrcQuenchs = value + procSnmp.Icmp.InSrcQuenchs = &value case "InRedirects": - procSnmp.Icmp.InRedirects = value + procSnmp.Icmp.InRedirects = &value case "InEchos": - procSnmp.Icmp.InEchos = value + procSnmp.Icmp.InEchos = &value case "InEchoReps": - procSnmp.Icmp.InEchoReps = value + procSnmp.Icmp.InEchoReps = &value case "InTimestamps": - procSnmp.Icmp.InTimestamps = value + procSnmp.Icmp.InTimestamps = &value case "InTimestampReps": - procSnmp.Icmp.InTimestampReps = value + procSnmp.Icmp.InTimestampReps = &value case "InAddrMasks": - procSnmp.Icmp.InAddrMasks = value + procSnmp.Icmp.InAddrMasks = &value case "InAddrMaskReps": - procSnmp.Icmp.InAddrMaskReps = value + procSnmp.Icmp.InAddrMaskReps = &value case "OutMsgs": - procSnmp.Icmp.OutMsgs = value + procSnmp.Icmp.OutMsgs = &value case "OutErrors": - procSnmp.Icmp.OutErrors = value + procSnmp.Icmp.OutErrors = &value case "OutDestUnreachs": - procSnmp.Icmp.OutDestUnreachs = value + procSnmp.Icmp.OutDestUnreachs = &value case "OutTimeExcds": - procSnmp.Icmp.OutTimeExcds = value + procSnmp.Icmp.OutTimeExcds = &value case "OutParmProbs": - procSnmp.Icmp.OutParmProbs = value + procSnmp.Icmp.OutParmProbs = &value case "OutSrcQuenchs": - procSnmp.Icmp.OutSrcQuenchs = value + procSnmp.Icmp.OutSrcQuenchs = &value case "OutRedirects": - procSnmp.Icmp.OutRedirects = value + procSnmp.Icmp.OutRedirects = &value case "OutEchos": - procSnmp.Icmp.OutEchos = value + procSnmp.Icmp.OutEchos = &value case "OutEchoReps": - procSnmp.Icmp.OutEchoReps = value + procSnmp.Icmp.OutEchoReps = &value case "OutTimestamps": - procSnmp.Icmp.OutTimestamps = value + procSnmp.Icmp.OutTimestamps = &value case "OutTimestampReps": - procSnmp.Icmp.OutTimestampReps = value + procSnmp.Icmp.OutTimestampReps = &value case "OutAddrMasks": - procSnmp.Icmp.OutAddrMasks = value + procSnmp.Icmp.OutAddrMasks = &value case "OutAddrMaskReps": - procSnmp.Icmp.OutAddrMaskReps = value + procSnmp.Icmp.OutAddrMaskReps = &value } case "IcmpMsg": switch key { case "InType3": - procSnmp.IcmpMsg.InType3 = value + procSnmp.IcmpMsg.InType3 = &value case "OutType3": - procSnmp.IcmpMsg.OutType3 = value + procSnmp.IcmpMsg.OutType3 = &value } case "Tcp": switch key { case "RtoAlgorithm": - procSnmp.Tcp.RtoAlgorithm = value + procSnmp.Tcp.RtoAlgorithm = &value case "RtoMin": - procSnmp.Tcp.RtoMin = value + procSnmp.Tcp.RtoMin = &value case "RtoMax": - procSnmp.Tcp.RtoMax = value + procSnmp.Tcp.RtoMax = &value case "MaxConn": - procSnmp.Tcp.MaxConn = value + procSnmp.Tcp.MaxConn = &value case "ActiveOpens": - procSnmp.Tcp.ActiveOpens = value + procSnmp.Tcp.ActiveOpens = &value case "PassiveOpens": - procSnmp.Tcp.PassiveOpens = value + procSnmp.Tcp.PassiveOpens = &value case "AttemptFails": - procSnmp.Tcp.AttemptFails = value + procSnmp.Tcp.AttemptFails = &value case "EstabResets": - procSnmp.Tcp.EstabResets = value + procSnmp.Tcp.EstabResets = &value case "CurrEstab": - procSnmp.Tcp.CurrEstab = value + procSnmp.Tcp.CurrEstab = &value case "InSegs": - procSnmp.Tcp.InSegs = value + procSnmp.Tcp.InSegs = &value case "OutSegs": - procSnmp.Tcp.OutSegs = value + procSnmp.Tcp.OutSegs = &value case "RetransSegs": - procSnmp.Tcp.RetransSegs = value + procSnmp.Tcp.RetransSegs = &value case "InErrs": - procSnmp.Tcp.InErrs = value + procSnmp.Tcp.InErrs = &value case "OutRsts": - procSnmp.Tcp.OutRsts = value + procSnmp.Tcp.OutRsts = &value case "InCsumErrors": - procSnmp.Tcp.InCsumErrors = value + procSnmp.Tcp.InCsumErrors = &value } case "Udp": switch key { case "InDatagrams": - procSnmp.Udp.InDatagrams = value + procSnmp.Udp.InDatagrams = &value case "NoPorts": - procSnmp.Udp.NoPorts = value + procSnmp.Udp.NoPorts = &value case "InErrors": - procSnmp.Udp.InErrors = value + procSnmp.Udp.InErrors = &value case "OutDatagrams": - procSnmp.Udp.OutDatagrams = value + procSnmp.Udp.OutDatagrams = &value case "RcvbufErrors": - procSnmp.Udp.RcvbufErrors = value + procSnmp.Udp.RcvbufErrors = &value case "SndbufErrors": - procSnmp.Udp.SndbufErrors = value + procSnmp.Udp.SndbufErrors = &value case "InCsumErrors": - procSnmp.Udp.InCsumErrors = value + procSnmp.Udp.InCsumErrors = &value case "IgnoredMulti": - procSnmp.Udp.IgnoredMulti = value + procSnmp.Udp.IgnoredMulti = &value } case "UdpLite": switch key { case "InDatagrams": - procSnmp.UdpLite.InDatagrams = value + procSnmp.UdpLite.InDatagrams = &value case "NoPorts": - procSnmp.UdpLite.NoPorts = value + procSnmp.UdpLite.NoPorts = &value case "InErrors": - procSnmp.UdpLite.InErrors = value + procSnmp.UdpLite.InErrors = &value case "OutDatagrams": - procSnmp.UdpLite.OutDatagrams = value + procSnmp.UdpLite.OutDatagrams = &value case "RcvbufErrors": - procSnmp.UdpLite.RcvbufErrors = value + procSnmp.UdpLite.RcvbufErrors = &value case "SndbufErrors": - procSnmp.UdpLite.SndbufErrors = value + procSnmp.UdpLite.SndbufErrors = &value case "InCsumErrors": - procSnmp.UdpLite.InCsumErrors = value + procSnmp.UdpLite.InCsumErrors = &value case "IgnoredMulti": - procSnmp.UdpLite.IgnoredMulti = value + procSnmp.UdpLite.IgnoredMulti = &value } } } diff --git a/vendor/github.com/prometheus/procfs/proc_snmp6.go b/vendor/github.com/prometheus/procfs/proc_snmp6.go index f611992d5..3059cc6a1 100644 --- a/vendor/github.com/prometheus/procfs/proc_snmp6.go +++ b/vendor/github.com/prometheus/procfs/proc_snmp6.go @@ -36,106 +36,106 @@ type ProcSnmp6 struct { } type Ip6 struct { // nolint:revive - InReceives float64 - InHdrErrors float64 - InTooBigErrors float64 - InNoRoutes float64 - InAddrErrors float64 - InUnknownProtos float64 - InTruncatedPkts float64 - InDiscards float64 - InDelivers float64 - OutForwDatagrams float64 - OutRequests float64 - OutDiscards float64 - OutNoRoutes float64 - ReasmTimeout float64 - ReasmReqds float64 - ReasmOKs float64 - ReasmFails float64 - FragOKs float64 - FragFails float64 - FragCreates float64 - InMcastPkts float64 - OutMcastPkts float64 - InOctets float64 - OutOctets float64 - InMcastOctets float64 - OutMcastOctets float64 - InBcastOctets float64 - OutBcastOctets float64 - InNoECTPkts float64 - InECT1Pkts float64 - InECT0Pkts float64 - InCEPkts float64 + InReceives *float64 + InHdrErrors *float64 + InTooBigErrors *float64 + InNoRoutes *float64 + InAddrErrors *float64 + InUnknownProtos *float64 + InTruncatedPkts *float64 + InDiscards *float64 + InDelivers *float64 + OutForwDatagrams *float64 + OutRequests *float64 + OutDiscards *float64 + OutNoRoutes *float64 + ReasmTimeout *float64 + ReasmReqds *float64 + ReasmOKs *float64 + ReasmFails *float64 + FragOKs *float64 + FragFails *float64 + FragCreates *float64 + InMcastPkts *float64 + OutMcastPkts *float64 + InOctets *float64 + OutOctets *float64 + InMcastOctets *float64 + OutMcastOctets *float64 + InBcastOctets *float64 + OutBcastOctets *float64 + InNoECTPkts *float64 + InECT1Pkts *float64 + InECT0Pkts *float64 + InCEPkts *float64 } type Icmp6 struct { - InMsgs float64 - InErrors float64 - OutMsgs float64 - OutErrors float64 - InCsumErrors float64 - InDestUnreachs float64 - InPktTooBigs float64 - InTimeExcds float64 - InParmProblems float64 - InEchos float64 - InEchoReplies float64 - InGroupMembQueries float64 - InGroupMembResponses float64 - InGroupMembReductions float64 - InRouterSolicits float64 - InRouterAdvertisements float64 - InNeighborSolicits float64 - InNeighborAdvertisements float64 - InRedirects float64 - InMLDv2Reports float64 - OutDestUnreachs float64 - OutPktTooBigs float64 - OutTimeExcds float64 - OutParmProblems float64 - OutEchos float64 - OutEchoReplies float64 - OutGroupMembQueries float64 - OutGroupMembResponses float64 - OutGroupMembReductions float64 - OutRouterSolicits float64 - OutRouterAdvertisements float64 - OutNeighborSolicits float64 - OutNeighborAdvertisements float64 - OutRedirects float64 - OutMLDv2Reports float64 - InType1 float64 - InType134 float64 - InType135 float64 - InType136 float64 - InType143 float64 - OutType133 float64 - OutType135 float64 - OutType136 float64 - OutType143 float64 + InMsgs *float64 + InErrors *float64 + OutMsgs *float64 + OutErrors *float64 + InCsumErrors *float64 + InDestUnreachs *float64 + InPktTooBigs *float64 + InTimeExcds *float64 + InParmProblems *float64 + InEchos *float64 + InEchoReplies *float64 + InGroupMembQueries *float64 + InGroupMembResponses *float64 + InGroupMembReductions *float64 + InRouterSolicits *float64 + InRouterAdvertisements *float64 + InNeighborSolicits *float64 + InNeighborAdvertisements *float64 + InRedirects *float64 + InMLDv2Reports *float64 + OutDestUnreachs *float64 + OutPktTooBigs *float64 + OutTimeExcds *float64 + OutParmProblems *float64 + OutEchos *float64 + OutEchoReplies *float64 + OutGroupMembQueries *float64 + OutGroupMembResponses *float64 + OutGroupMembReductions *float64 + OutRouterSolicits *float64 + OutRouterAdvertisements *float64 + OutNeighborSolicits *float64 + OutNeighborAdvertisements *float64 + OutRedirects *float64 + OutMLDv2Reports *float64 + InType1 *float64 + InType134 *float64 + InType135 *float64 + InType136 *float64 + InType143 *float64 + OutType133 *float64 + OutType135 *float64 + OutType136 *float64 + OutType143 *float64 } type Udp6 struct { // nolint:revive - InDatagrams float64 - NoPorts float64 - InErrors float64 - OutDatagrams float64 - RcvbufErrors float64 - SndbufErrors float64 - InCsumErrors float64 - IgnoredMulti float64 + InDatagrams *float64 + NoPorts *float64 + InErrors *float64 + OutDatagrams *float64 + RcvbufErrors *float64 + SndbufErrors *float64 + InCsumErrors *float64 + IgnoredMulti *float64 } type UdpLite6 struct { // nolint:revive - InDatagrams float64 - NoPorts float64 - InErrors float64 - OutDatagrams float64 - RcvbufErrors float64 - SndbufErrors float64 - InCsumErrors float64 + InDatagrams *float64 + NoPorts *float64 + InErrors *float64 + OutDatagrams *float64 + RcvbufErrors *float64 + SndbufErrors *float64 + InCsumErrors *float64 } func (p Proc) Snmp6() (ProcSnmp6, error) { @@ -182,197 +182,197 @@ func parseSNMP6Stats(r io.Reader) (ProcSnmp6, error) { case "Ip6": switch key { case "InReceives": - procSnmp6.Ip6.InReceives = value + procSnmp6.Ip6.InReceives = &value case "InHdrErrors": - procSnmp6.Ip6.InHdrErrors = value + procSnmp6.Ip6.InHdrErrors = &value case "InTooBigErrors": - procSnmp6.Ip6.InTooBigErrors = value + procSnmp6.Ip6.InTooBigErrors = &value case "InNoRoutes": - procSnmp6.Ip6.InNoRoutes = value + procSnmp6.Ip6.InNoRoutes = &value case "InAddrErrors": - procSnmp6.Ip6.InAddrErrors = value + procSnmp6.Ip6.InAddrErrors = &value case "InUnknownProtos": - procSnmp6.Ip6.InUnknownProtos = value + procSnmp6.Ip6.InUnknownProtos = &value case "InTruncatedPkts": - procSnmp6.Ip6.InTruncatedPkts = value + procSnmp6.Ip6.InTruncatedPkts = &value case "InDiscards": - procSnmp6.Ip6.InDiscards = value + procSnmp6.Ip6.InDiscards = &value case "InDelivers": - procSnmp6.Ip6.InDelivers = value + procSnmp6.Ip6.InDelivers = &value case "OutForwDatagrams": - procSnmp6.Ip6.OutForwDatagrams = value + procSnmp6.Ip6.OutForwDatagrams = &value case "OutRequests": - procSnmp6.Ip6.OutRequests = value + procSnmp6.Ip6.OutRequests = &value case "OutDiscards": - procSnmp6.Ip6.OutDiscards = value + procSnmp6.Ip6.OutDiscards = &value case "OutNoRoutes": - procSnmp6.Ip6.OutNoRoutes = value + procSnmp6.Ip6.OutNoRoutes = &value case "ReasmTimeout": - procSnmp6.Ip6.ReasmTimeout = value + procSnmp6.Ip6.ReasmTimeout = &value case "ReasmReqds": - procSnmp6.Ip6.ReasmReqds = value + procSnmp6.Ip6.ReasmReqds = &value case "ReasmOKs": - procSnmp6.Ip6.ReasmOKs = value + procSnmp6.Ip6.ReasmOKs = &value case "ReasmFails": - procSnmp6.Ip6.ReasmFails = value + procSnmp6.Ip6.ReasmFails = &value case "FragOKs": - procSnmp6.Ip6.FragOKs = value + procSnmp6.Ip6.FragOKs = &value case "FragFails": - procSnmp6.Ip6.FragFails = value + procSnmp6.Ip6.FragFails = &value case "FragCreates": - procSnmp6.Ip6.FragCreates = value + procSnmp6.Ip6.FragCreates = &value case "InMcastPkts": - procSnmp6.Ip6.InMcastPkts = value + procSnmp6.Ip6.InMcastPkts = &value case "OutMcastPkts": - procSnmp6.Ip6.OutMcastPkts = value + procSnmp6.Ip6.OutMcastPkts = &value case "InOctets": - procSnmp6.Ip6.InOctets = value + procSnmp6.Ip6.InOctets = &value case "OutOctets": - procSnmp6.Ip6.OutOctets = value + procSnmp6.Ip6.OutOctets = &value case "InMcastOctets": - procSnmp6.Ip6.InMcastOctets = value + procSnmp6.Ip6.InMcastOctets = &value case "OutMcastOctets": - procSnmp6.Ip6.OutMcastOctets = value + procSnmp6.Ip6.OutMcastOctets = &value case "InBcastOctets": - procSnmp6.Ip6.InBcastOctets = value + procSnmp6.Ip6.InBcastOctets = &value case "OutBcastOctets": - procSnmp6.Ip6.OutBcastOctets = value + procSnmp6.Ip6.OutBcastOctets = &value case "InNoECTPkts": - procSnmp6.Ip6.InNoECTPkts = value + procSnmp6.Ip6.InNoECTPkts = &value case "InECT1Pkts": - procSnmp6.Ip6.InECT1Pkts = value + procSnmp6.Ip6.InECT1Pkts = &value case "InECT0Pkts": - procSnmp6.Ip6.InECT0Pkts = value + procSnmp6.Ip6.InECT0Pkts = &value case "InCEPkts": - procSnmp6.Ip6.InCEPkts = value + procSnmp6.Ip6.InCEPkts = &value } case "Icmp6": switch key { case "InMsgs": - procSnmp6.Icmp6.InMsgs = value + procSnmp6.Icmp6.InMsgs = &value case "InErrors": - procSnmp6.Icmp6.InErrors = value + procSnmp6.Icmp6.InErrors = &value case "OutMsgs": - procSnmp6.Icmp6.OutMsgs = value + procSnmp6.Icmp6.OutMsgs = &value case "OutErrors": - procSnmp6.Icmp6.OutErrors = value + procSnmp6.Icmp6.OutErrors = &value case "InCsumErrors": - procSnmp6.Icmp6.InCsumErrors = value + procSnmp6.Icmp6.InCsumErrors = &value case "InDestUnreachs": - procSnmp6.Icmp6.InDestUnreachs = value + procSnmp6.Icmp6.InDestUnreachs = &value case "InPktTooBigs": - procSnmp6.Icmp6.InPktTooBigs = value + procSnmp6.Icmp6.InPktTooBigs = &value case "InTimeExcds": - procSnmp6.Icmp6.InTimeExcds = value + procSnmp6.Icmp6.InTimeExcds = &value case "InParmProblems": - procSnmp6.Icmp6.InParmProblems = value + procSnmp6.Icmp6.InParmProblems = &value case "InEchos": - procSnmp6.Icmp6.InEchos = value + procSnmp6.Icmp6.InEchos = &value case "InEchoReplies": - procSnmp6.Icmp6.InEchoReplies = value + procSnmp6.Icmp6.InEchoReplies = &value case "InGroupMembQueries": - procSnmp6.Icmp6.InGroupMembQueries = value + procSnmp6.Icmp6.InGroupMembQueries = &value case "InGroupMembResponses": - procSnmp6.Icmp6.InGroupMembResponses = value + procSnmp6.Icmp6.InGroupMembResponses = &value case "InGroupMembReductions": - procSnmp6.Icmp6.InGroupMembReductions = value + procSnmp6.Icmp6.InGroupMembReductions = &value case "InRouterSolicits": - procSnmp6.Icmp6.InRouterSolicits = value + procSnmp6.Icmp6.InRouterSolicits = &value case "InRouterAdvertisements": - procSnmp6.Icmp6.InRouterAdvertisements = value + procSnmp6.Icmp6.InRouterAdvertisements = &value case "InNeighborSolicits": - procSnmp6.Icmp6.InNeighborSolicits = value + procSnmp6.Icmp6.InNeighborSolicits = &value case "InNeighborAdvertisements": - procSnmp6.Icmp6.InNeighborAdvertisements = value + procSnmp6.Icmp6.InNeighborAdvertisements = &value case "InRedirects": - procSnmp6.Icmp6.InRedirects = value + procSnmp6.Icmp6.InRedirects = &value case "InMLDv2Reports": - procSnmp6.Icmp6.InMLDv2Reports = value + procSnmp6.Icmp6.InMLDv2Reports = &value case "OutDestUnreachs": - procSnmp6.Icmp6.OutDestUnreachs = value + procSnmp6.Icmp6.OutDestUnreachs = &value case "OutPktTooBigs": - procSnmp6.Icmp6.OutPktTooBigs = value + procSnmp6.Icmp6.OutPktTooBigs = &value case "OutTimeExcds": - procSnmp6.Icmp6.OutTimeExcds = value + procSnmp6.Icmp6.OutTimeExcds = &value case "OutParmProblems": - procSnmp6.Icmp6.OutParmProblems = value + procSnmp6.Icmp6.OutParmProblems = &value case "OutEchos": - procSnmp6.Icmp6.OutEchos = value + procSnmp6.Icmp6.OutEchos = &value case "OutEchoReplies": - procSnmp6.Icmp6.OutEchoReplies = value + procSnmp6.Icmp6.OutEchoReplies = &value case "OutGroupMembQueries": - procSnmp6.Icmp6.OutGroupMembQueries = value + procSnmp6.Icmp6.OutGroupMembQueries = &value case "OutGroupMembResponses": - procSnmp6.Icmp6.OutGroupMembResponses = value + procSnmp6.Icmp6.OutGroupMembResponses = &value case "OutGroupMembReductions": - procSnmp6.Icmp6.OutGroupMembReductions = value + procSnmp6.Icmp6.OutGroupMembReductions = &value case "OutRouterSolicits": - procSnmp6.Icmp6.OutRouterSolicits = value + procSnmp6.Icmp6.OutRouterSolicits = &value case "OutRouterAdvertisements": - procSnmp6.Icmp6.OutRouterAdvertisements = value + procSnmp6.Icmp6.OutRouterAdvertisements = &value case "OutNeighborSolicits": - procSnmp6.Icmp6.OutNeighborSolicits = value + procSnmp6.Icmp6.OutNeighborSolicits = &value case "OutNeighborAdvertisements": - procSnmp6.Icmp6.OutNeighborAdvertisements = value + procSnmp6.Icmp6.OutNeighborAdvertisements = &value case "OutRedirects": - procSnmp6.Icmp6.OutRedirects = value + procSnmp6.Icmp6.OutRedirects = &value case "OutMLDv2Reports": - procSnmp6.Icmp6.OutMLDv2Reports = value + procSnmp6.Icmp6.OutMLDv2Reports = &value case "InType1": - procSnmp6.Icmp6.InType1 = value + procSnmp6.Icmp6.InType1 = &value case "InType134": - procSnmp6.Icmp6.InType134 = value + procSnmp6.Icmp6.InType134 = &value case "InType135": - procSnmp6.Icmp6.InType135 = value + procSnmp6.Icmp6.InType135 = &value case "InType136": - procSnmp6.Icmp6.InType136 = value + procSnmp6.Icmp6.InType136 = &value case "InType143": - procSnmp6.Icmp6.InType143 = value + procSnmp6.Icmp6.InType143 = &value case "OutType133": - procSnmp6.Icmp6.OutType133 = value + procSnmp6.Icmp6.OutType133 = &value case "OutType135": - procSnmp6.Icmp6.OutType135 = value + procSnmp6.Icmp6.OutType135 = &value case "OutType136": - procSnmp6.Icmp6.OutType136 = value + procSnmp6.Icmp6.OutType136 = &value case "OutType143": - procSnmp6.Icmp6.OutType143 = value + procSnmp6.Icmp6.OutType143 = &value } case "Udp6": switch key { case "InDatagrams": - procSnmp6.Udp6.InDatagrams = value + procSnmp6.Udp6.InDatagrams = &value case "NoPorts": - procSnmp6.Udp6.NoPorts = value + procSnmp6.Udp6.NoPorts = &value case "InErrors": - procSnmp6.Udp6.InErrors = value + procSnmp6.Udp6.InErrors = &value case "OutDatagrams": - procSnmp6.Udp6.OutDatagrams = value + procSnmp6.Udp6.OutDatagrams = &value case "RcvbufErrors": - procSnmp6.Udp6.RcvbufErrors = value + procSnmp6.Udp6.RcvbufErrors = &value case "SndbufErrors": - procSnmp6.Udp6.SndbufErrors = value + procSnmp6.Udp6.SndbufErrors = &value case "InCsumErrors": - procSnmp6.Udp6.InCsumErrors = value + procSnmp6.Udp6.InCsumErrors = &value case "IgnoredMulti": - procSnmp6.Udp6.IgnoredMulti = value + procSnmp6.Udp6.IgnoredMulti = &value } case "UdpLite6": switch key { case "InDatagrams": - procSnmp6.UdpLite6.InDatagrams = value + procSnmp6.UdpLite6.InDatagrams = &value case "NoPorts": - procSnmp6.UdpLite6.NoPorts = value + procSnmp6.UdpLite6.NoPorts = &value case "InErrors": - procSnmp6.UdpLite6.InErrors = value + procSnmp6.UdpLite6.InErrors = &value case "OutDatagrams": - procSnmp6.UdpLite6.OutDatagrams = value + procSnmp6.UdpLite6.OutDatagrams = &value case "RcvbufErrors": - procSnmp6.UdpLite6.RcvbufErrors = value + procSnmp6.UdpLite6.RcvbufErrors = &value case "SndbufErrors": - procSnmp6.UdpLite6.SndbufErrors = value + procSnmp6.UdpLite6.SndbufErrors = &value case "InCsumErrors": - procSnmp6.UdpLite6.InCsumErrors = value + procSnmp6.UdpLite6.InCsumErrors = &value } } } diff --git a/vendor/github.com/prometheus/procfs/proc_stat.go b/vendor/github.com/prometheus/procfs/proc_stat.go index 06c556ef9..923e55005 100644 --- a/vendor/github.com/prometheus/procfs/proc_stat.go +++ b/vendor/github.com/prometheus/procfs/proc_stat.go @@ -18,7 +18,6 @@ import ( "fmt" "os" - "github.com/prometheus/procfs/internal/fs" "github.com/prometheus/procfs/internal/util" ) @@ -102,6 +101,8 @@ type ProcStat struct { RSS int // Soft limit in bytes on the rss of the process. RSSLimit uint64 + // CPU number last executed on. + Processor uint // Real-time scheduling priority, a number in the range 1 to 99 for processes // scheduled under a real-time policy, or 0, for non-real-time processes. RTPriority uint @@ -110,7 +111,7 @@ type ProcStat struct { // Aggregated block I/O delays, measured in clock ticks (centiseconds). DelayAcctBlkIOTicks uint64 - proc fs.FS + proc FS } // NewStat returns the current status information of the process. @@ -137,7 +138,7 @@ func (p Proc) Stat() (ProcStat, error) { ) if l < 0 || r < 0 { - return ProcStat{}, fmt.Errorf("unexpected format, couldn't extract comm %q", data) + return ProcStat{}, fmt.Errorf("%w: unexpected format, couldn't extract comm %q", ErrFileParse, data) } s.Comm = string(data[l+1 : r]) @@ -184,7 +185,7 @@ func (p Proc) Stat() (ProcStat, error) { &ignoreUint64, &ignoreUint64, &ignoreInt64, - &ignoreInt64, + &s.Processor, &s.RTPriority, &s.Policy, &s.DelayAcctBlkIOTicks, @@ -208,8 +209,7 @@ func (s ProcStat) ResidentMemory() int { // StartTime returns the unix timestamp of the process in seconds. func (s ProcStat) StartTime() (float64, error) { - fs := FS{proc: s.proc} - stat, err := fs.Stat() + stat, err := s.proc.Stat() if err != nil { return 0, err } diff --git a/vendor/github.com/prometheus/procfs/proc_status.go b/vendor/github.com/prometheus/procfs/proc_status.go index 594022ded..46307f572 100644 --- a/vendor/github.com/prometheus/procfs/proc_status.go +++ b/vendor/github.com/prometheus/procfs/proc_status.go @@ -15,6 +15,7 @@ package procfs import ( "bytes" + "sort" "strconv" "strings" @@ -22,7 +23,7 @@ import ( ) // ProcStatus provides status information about the process, -// read from /proc/[pid]/stat. +// read from /proc/[pid]/status. type ProcStatus struct { // The process ID. PID int @@ -31,6 +32,8 @@ type ProcStatus struct { // Thread group ID. TGID int + // List of Pid namespace. + NSpids []uint64 // Peak virtual memory size. VmPeak uint64 // nolint:revive @@ -76,6 +79,9 @@ type ProcStatus struct { UIDs [4]string // GIDs of the process (Real, effective, saved set, and filesystem GIDs) GIDs [4]string + + // CpusAllowedList: List of cpu cores processes are allowed to run on. + CpusAllowedList []uint64 } // NewStatus returns the current status information of the process. @@ -96,10 +102,10 @@ func (p Proc) NewStatus() (ProcStatus, error) { kv := strings.SplitN(line, ":", 2) // removes spaces - k := string(strings.TrimSpace(kv[0])) - v := string(strings.TrimSpace(kv[1])) + k := strings.TrimSpace(kv[0]) + v := strings.TrimSpace(kv[1]) // removes "kB" - v = string(bytes.Trim([]byte(v), " kB")) + v = strings.TrimSuffix(v, " kB") // value to int when possible // we can skip error check here, 'cause vKBytes is not used when value is a string @@ -123,6 +129,8 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt copy(s.UIDs[:], strings.Split(vString, "\t")) case "Gid": copy(s.GIDs[:], strings.Split(vString, "\t")) + case "NSpid": + s.NSpids = calcNSPidsList(vString) case "VmPeak": s.VmPeak = vUintBytes case "VmSize": @@ -161,10 +169,53 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt s.VoluntaryCtxtSwitches = vUint case "nonvoluntary_ctxt_switches": s.NonVoluntaryCtxtSwitches = vUint + case "Cpus_allowed_list": + s.CpusAllowedList = calcCpusAllowedList(vString) } + } // TotalCtxtSwitches returns the total context switch. func (s ProcStatus) TotalCtxtSwitches() uint64 { return s.VoluntaryCtxtSwitches + s.NonVoluntaryCtxtSwitches } + +func calcCpusAllowedList(cpuString string) []uint64 { + s := strings.Split(cpuString, ",") + + var g []uint64 + + for _, cpu := range s { + // parse cpu ranges, example: 1-3=[1,2,3] + if l := strings.Split(strings.TrimSpace(cpu), "-"); len(l) > 1 { + startCPU, _ := strconv.ParseUint(l[0], 10, 64) + endCPU, _ := strconv.ParseUint(l[1], 10, 64) + + for i := startCPU; i <= endCPU; i++ { + g = append(g, i) + } + } else if len(l) == 1 { + cpu, _ := strconv.ParseUint(l[0], 10, 64) + g = append(g, cpu) + } + + } + + sort.Slice(g, func(i, j int) bool { return g[i] < g[j] }) + return g +} + +func calcNSPidsList(nspidsString string) []uint64 { + s := strings.Split(nspidsString, " ") + var nspids []uint64 + + for _, nspid := range s { + nspid, _ := strconv.ParseUint(nspid, 10, 64) + if nspid == 0 { + continue + } + nspids = append(nspids, nspid) + } + + return nspids +} diff --git a/vendor/github.com/prometheus/procfs/proc_sys.go b/vendor/github.com/prometheus/procfs/proc_sys.go index d46533ebf..12c5bf05b 100644 --- a/vendor/github.com/prometheus/procfs/proc_sys.go +++ b/vendor/github.com/prometheus/procfs/proc_sys.go @@ -44,7 +44,7 @@ func (fs FS) SysctlInts(sysctl string) ([]int, error) { vp := util.NewValueParser(f) values[i] = vp.Int() if err := vp.Err(); err != nil { - return nil, fmt.Errorf("field %d in sysctl %s is not a valid int: %w", i, sysctl, err) + return nil, fmt.Errorf("%s: field %d in sysctl %s is not a valid int: %w", ErrFileParse, i, sysctl, err) } } return values, nil diff --git a/vendor/github.com/prometheus/procfs/slab.go b/vendor/github.com/prometheus/procfs/slab.go index bc9aaf5c2..8611c9017 100644 --- a/vendor/github.com/prometheus/procfs/slab.go +++ b/vendor/github.com/prometheus/procfs/slab.go @@ -68,7 +68,7 @@ func parseV21SlabEntry(line string) (*Slab, error) { l := slabSpace.ReplaceAllString(line, " ") s := strings.Split(l, " ") if len(s) != 16 { - return nil, fmt.Errorf("unable to parse: %q", line) + return nil, fmt.Errorf("%w: unable to parse: %q", ErrFileParse, line) } var err error i := &Slab{Name: s[0]} diff --git a/vendor/github.com/prometheus/procfs/softirqs.go b/vendor/github.com/prometheus/procfs/softirqs.go index 559129cbc..b8fad677d 100644 --- a/vendor/github.com/prometheus/procfs/softirqs.go +++ b/vendor/github.com/prometheus/procfs/softirqs.go @@ -57,7 +57,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { ) if !scanner.Scan() { - return Softirqs{}, fmt.Errorf("softirqs empty") + return Softirqs{}, fmt.Errorf("%w: softirqs empty", ErrFileRead) } for scanner.Scan() { @@ -74,7 +74,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Hi = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Hi[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (HI%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (HI%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "TIMER:": @@ -82,7 +82,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Timer = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Timer[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (TIMER%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (TIMER%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "NET_TX:": @@ -90,7 +90,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.NetTx = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.NetTx[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (NET_TX%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (NET_TX%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "NET_RX:": @@ -98,7 +98,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.NetRx = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.NetRx[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (NET_RX%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (NET_RX%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "BLOCK:": @@ -106,7 +106,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Block = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Block[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (BLOCK%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (BLOCK%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "IRQ_POLL:": @@ -114,7 +114,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.IRQPoll = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.IRQPoll[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (IRQ_POLL%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (IRQ_POLL%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "TASKLET:": @@ -122,7 +122,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Tasklet = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Tasklet[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (TASKLET%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (TASKLET%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "SCHED:": @@ -130,7 +130,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.Sched = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.Sched[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (SCHED%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (SCHED%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "HRTIMER:": @@ -138,7 +138,7 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.HRTimer = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.HRTimer[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (HRTIMER%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (HRTIMER%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "RCU:": @@ -146,14 +146,14 @@ func parseSoftirqs(r io.Reader) (Softirqs, error) { softirqs.RCU = make([]uint64, len(perCPU)) for i, count := range perCPU { if softirqs.RCU[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse %q (RCU%d): %w", count, i, err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse %q (RCU%d): %w", ErrFileParse, count, i, err) } } } } if err := scanner.Err(); err != nil { - return Softirqs{}, fmt.Errorf("couldn't parse softirqs: %w", err) + return Softirqs{}, fmt.Errorf("%s: couldn't parse softirqs: %w", ErrFileParse, err) } return softirqs, scanner.Err() diff --git a/vendor/github.com/prometheus/procfs/stat.go b/vendor/github.com/prometheus/procfs/stat.go index 33f97caa0..34fc3ee21 100644 --- a/vendor/github.com/prometheus/procfs/stat.go +++ b/vendor/github.com/prometheus/procfs/stat.go @@ -62,7 +62,7 @@ type Stat struct { // Summed up cpu statistics. CPUTotal CPUStat // Per-CPU statistics. - CPU []CPUStat + CPU map[int64]CPUStat // Number of times interrupts were handled, which contains numbered and unnumbered IRQs. IRQTotal uint64 // Number of times a numbered IRQ was triggered. @@ -93,10 +93,10 @@ func parseCPUStat(line string) (CPUStat, int64, error) { &cpuStat.Guest, &cpuStat.GuestNice) if err != nil && err != io.EOF { - return CPUStat{}, -1, fmt.Errorf("couldn't parse %q (cpu): %w", line, err) + return CPUStat{}, -1, fmt.Errorf("%s: couldn't parse %q (cpu): %w", ErrFileParse, line, err) } if count == 0 { - return CPUStat{}, -1, fmt.Errorf("couldn't parse %q (cpu): 0 elements parsed", line) + return CPUStat{}, -1, fmt.Errorf("%w: couldn't parse %q (cpu): 0 elements parsed", ErrFileParse, line) } cpuStat.User /= userHZ @@ -116,7 +116,7 @@ func parseCPUStat(line string) (CPUStat, int64, error) { cpuID, err := strconv.ParseInt(cpu[3:], 10, 64) if err != nil { - return CPUStat{}, -1, fmt.Errorf("couldn't parse %q (cpu/cpuid): %w", line, err) + return CPUStat{}, -1, fmt.Errorf("%s: couldn't parse %q (cpu/cpuid): %w", ErrFileParse, line, err) } return cpuStat, cpuID, nil @@ -136,7 +136,7 @@ func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) { &softIRQStat.Hrtimer, &softIRQStat.Rcu) if err != nil { - return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %q (softirq): %w", line, err) + return SoftIRQStat{}, 0, fmt.Errorf("%s: couldn't parse %q (softirq): %w", ErrFileParse, line, err) } return softIRQStat, total, nil @@ -170,10 +170,27 @@ func (fs FS) Stat() (Stat, error) { if err != nil { return Stat{}, err } + procStat, err := parseStat(bytes.NewReader(data), fileName) + if err != nil { + return Stat{}, err + } + return procStat, nil +} - stat := Stat{} +// parseStat parses the metrics from /proc/[pid]/stat. +func parseStat(r io.Reader, fileName string) (Stat, error) { + var ( + scanner = bufio.NewScanner(r) + stat = Stat{ + CPU: make(map[int64]CPUStat), + } + err error + ) + + // Increase default scanner buffer to handle very long `intr` lines. + buf := make([]byte, 0, 8*1024) + scanner.Buffer(buf, 1024*1024) - scanner := bufio.NewScanner(bytes.NewReader(data)) for scanner.Scan() { line := scanner.Text() parts := strings.Fields(scanner.Text()) @@ -184,34 +201,34 @@ func (fs FS) Stat() (Stat, error) { switch { case parts[0] == "btime": if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (btime): %w", parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (btime): %w", ErrFileParse, parts[1], err) } case parts[0] == "intr": if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (intr): %w", parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (intr): %w", ErrFileParse, parts[1], err) } numberedIRQs := parts[2:] stat.IRQ = make([]uint64, len(numberedIRQs)) for i, count := range numberedIRQs { if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (intr%d): %w", count, i, err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (intr%d): %w", ErrFileParse, count, i, err) } } case parts[0] == "ctxt": if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (ctxt): %w", parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (ctxt): %w", ErrFileParse, parts[1], err) } case parts[0] == "processes": if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (processes): %w", parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (processes): %w", ErrFileParse, parts[1], err) } case parts[0] == "procs_running": if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (procs_running): %w", parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (procs_running): %w", ErrFileParse, parts[1], err) } case parts[0] == "procs_blocked": if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q (procs_blocked): %w", parts[1], err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q (procs_blocked): %w", ErrFileParse, parts[1], err) } case parts[0] == "softirq": softIRQStats, total, err := parseSoftIRQStat(line) @@ -228,16 +245,13 @@ func (fs FS) Stat() (Stat, error) { if cpuID == -1 { stat.CPUTotal = cpuStat } else { - for int64(len(stat.CPU)) <= cpuID { - stat.CPU = append(stat.CPU, CPUStat{}) - } stat.CPU[cpuID] = cpuStat } } } if err := scanner.Err(); err != nil { - return Stat{}, fmt.Errorf("couldn't parse %q: %w", fileName, err) + return Stat{}, fmt.Errorf("%s: couldn't parse %q: %w", ErrFileParse, fileName, err) } return stat, nil diff --git a/vendor/github.com/prometheus/procfs/swaps.go b/vendor/github.com/prometheus/procfs/swaps.go index 15edc2212..fa00f555d 100644 --- a/vendor/github.com/prometheus/procfs/swaps.go +++ b/vendor/github.com/prometheus/procfs/swaps.go @@ -64,7 +64,7 @@ func parseSwapString(swapString string) (*Swap, error) { swapFields := strings.Fields(swapString) swapLength := len(swapFields) if swapLength < 5 { - return nil, fmt.Errorf("too few fields in swap string: %s", swapString) + return nil, fmt.Errorf("%w: too few fields in swap string: %s", ErrFileParse, swapString) } swap := &Swap{ @@ -74,15 +74,15 @@ func parseSwapString(swapString string) (*Swap, error) { swap.Size, err = strconv.Atoi(swapFields[2]) if err != nil { - return nil, fmt.Errorf("invalid swap size: %s", swapFields[2]) + return nil, fmt.Errorf("%s: invalid swap size: %s: %w", ErrFileParse, swapFields[2], err) } swap.Used, err = strconv.Atoi(swapFields[3]) if err != nil { - return nil, fmt.Errorf("invalid swap used: %s", swapFields[3]) + return nil, fmt.Errorf("%s: invalid swap used: %s: %w", ErrFileParse, swapFields[3], err) } swap.Priority, err = strconv.Atoi(swapFields[4]) if err != nil { - return nil, fmt.Errorf("invalid swap priority: %s", swapFields[4]) + return nil, fmt.Errorf("%s: invalid swap priority: %s: %w", ErrFileParse, swapFields[4], err) } return swap, nil diff --git a/vendor/github.com/prometheus/procfs/thread.go b/vendor/github.com/prometheus/procfs/thread.go new file mode 100644 index 000000000..df2215ece --- /dev/null +++ b/vendor/github.com/prometheus/procfs/thread.go @@ -0,0 +1,80 @@ +// Copyright 2022 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 procfs + +import ( + "fmt" + "os" + "strconv" + + fsi "github.com/prometheus/procfs/internal/fs" +) + +// Provide access to /proc/PID/task/TID files, for thread specific values. Since +// such files have the same structure as /proc/PID/ ones, the data structures +// and the parsers for the latter may be reused. + +// AllThreads returns a list of all currently available threads under /proc/PID. +func AllThreads(pid int) (Procs, error) { + fs, err := NewFS(DefaultMountPoint) + if err != nil { + return Procs{}, err + } + return fs.AllThreads(pid) +} + +// AllThreads returns a list of all currently available threads for PID. +func (fs FS) AllThreads(pid int) (Procs, error) { + taskPath := fs.proc.Path(strconv.Itoa(pid), "task") + d, err := os.Open(taskPath) + if err != nil { + return Procs{}, err + } + defer d.Close() + + names, err := d.Readdirnames(-1) + if err != nil { + return Procs{}, fmt.Errorf("%s: could not read %q: %w", ErrFileRead, d.Name(), err) + } + + t := Procs{} + for _, n := range names { + tid, err := strconv.ParseInt(n, 10, 64) + if err != nil { + continue + } + + t = append(t, Proc{PID: int(tid), fs: FS{fsi.FS(taskPath), fs.isReal}}) + } + + return t, nil +} + +// Thread returns a process for a given PID, TID. +func (fs FS) Thread(pid, tid int) (Proc, error) { + taskPath := fs.proc.Path(strconv.Itoa(pid), "task") + if _, err := os.Stat(taskPath); err != nil { + return Proc{}, err + } + return Proc{PID: tid, fs: FS{fsi.FS(taskPath), fs.isReal}}, nil +} + +// Thread returns a process for a given TID of Proc. +func (proc Proc) Thread(tid int) (Proc, error) { + tfs := FS{fsi.FS(proc.path("task")), proc.fs.isReal} + if _, err := os.Stat(tfs.proc.Path(strconv.Itoa(tid))); err != nil { + return Proc{}, err + } + return Proc{PID: tid, fs: tfs}, nil +} diff --git a/vendor/github.com/prometheus/procfs/vm.go b/vendor/github.com/prometheus/procfs/vm.go index 20ceb77e2..51c49d89e 100644 --- a/vendor/github.com/prometheus/procfs/vm.go +++ b/vendor/github.com/prometheus/procfs/vm.go @@ -26,7 +26,9 @@ import ( ) // The VM interface is described at -// https://www.kernel.org/doc/Documentation/sysctl/vm.txt +// +// https://www.kernel.org/doc/Documentation/sysctl/vm.txt +// // Each setting is exposed as a single file. // Each file contains one line with a single numerical value, except lowmem_reserve_ratio which holds an array // and numa_zonelist_order (deprecated) which is a string. @@ -84,7 +86,7 @@ func (fs FS) VM() (*VM, error) { return nil, err } if !file.Mode().IsDir() { - return nil, fmt.Errorf("%s is not a directory", path) + return nil, fmt.Errorf("%w: %s is not a directory", ErrFileRead, path) } files, err := os.ReadDir(path) diff --git a/vendor/github.com/prometheus/procfs/zoneinfo.go b/vendor/github.com/prometheus/procfs/zoneinfo.go index c745a4c04..ce5fefa5b 100644 --- a/vendor/github.com/prometheus/procfs/zoneinfo.go +++ b/vendor/github.com/prometheus/procfs/zoneinfo.go @@ -75,11 +75,11 @@ var nodeZoneRE = regexp.MustCompile(`(\d+), zone\s+(\w+)`) func (fs FS) Zoneinfo() ([]Zoneinfo, error) { data, err := os.ReadFile(fs.proc.Path("zoneinfo")) if err != nil { - return nil, fmt.Errorf("error reading zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err) + return nil, fmt.Errorf("%s: error reading zoneinfo %q: %w", ErrFileRead, fs.proc.Path("zoneinfo"), err) } zoneinfo, err := parseZoneinfo(data) if err != nil { - return nil, fmt.Errorf("error parsing zoneinfo %q: %w", fs.proc.Path("zoneinfo"), err) + return nil, fmt.Errorf("%s: error parsing zoneinfo %q: %w", ErrFileParse, fs.proc.Path("zoneinfo"), err) } return zoneinfo, nil } diff --git a/vendor/golang.org/x/net/http2/databuffer.go b/vendor/golang.org/x/net/http2/databuffer.go index a3067f8de..e6f55cbd1 100644 --- a/vendor/golang.org/x/net/http2/databuffer.go +++ b/vendor/golang.org/x/net/http2/databuffer.go @@ -20,41 +20,44 @@ import ( // TODO: Benchmark to determine if the pools are necessary. The GC may have // improved enough that we can instead allocate chunks like this: // make([]byte, max(16<<10, expectedBytesRemaining)) -var ( - dataChunkSizeClasses = []int{ - 1 << 10, - 2 << 10, - 4 << 10, - 8 << 10, - 16 << 10, - } - dataChunkPools = [...]sync.Pool{ - {New: func() interface{} { return make([]byte, 1<<10) }}, - {New: func() interface{} { return make([]byte, 2<<10) }}, - {New: func() interface{} { return make([]byte, 4<<10) }}, - {New: func() interface{} { return make([]byte, 8<<10) }}, - {New: func() interface{} { return make([]byte, 16<<10) }}, - } -) +var dataChunkPools = [...]sync.Pool{ + {New: func() interface{} { return new([1 << 10]byte) }}, + {New: func() interface{} { return new([2 << 10]byte) }}, + {New: func() interface{} { return new([4 << 10]byte) }}, + {New: func() interface{} { return new([8 << 10]byte) }}, + {New: func() interface{} { return new([16 << 10]byte) }}, +} func getDataBufferChunk(size int64) []byte { - i := 0 - for ; i < len(dataChunkSizeClasses)-1; i++ { - if size <= int64(dataChunkSizeClasses[i]) { - break - } + switch { + case size <= 1<<10: + return dataChunkPools[0].Get().(*[1 << 10]byte)[:] + case size <= 2<<10: + return dataChunkPools[1].Get().(*[2 << 10]byte)[:] + case size <= 4<<10: + return dataChunkPools[2].Get().(*[4 << 10]byte)[:] + case size <= 8<<10: + return dataChunkPools[3].Get().(*[8 << 10]byte)[:] + default: + return dataChunkPools[4].Get().(*[16 << 10]byte)[:] } - return dataChunkPools[i].Get().([]byte) } func putDataBufferChunk(p []byte) { - for i, n := range dataChunkSizeClasses { - if len(p) == n { - dataChunkPools[i].Put(p) - return - } + switch len(p) { + case 1 << 10: + dataChunkPools[0].Put((*[1 << 10]byte)(p)) + case 2 << 10: + dataChunkPools[1].Put((*[2 << 10]byte)(p)) + case 4 << 10: + dataChunkPools[2].Put((*[4 << 10]byte)(p)) + case 8 << 10: + dataChunkPools[3].Put((*[8 << 10]byte)(p)) + case 16 << 10: + dataChunkPools[4].Put((*[16 << 10]byte)(p)) + default: + panic(fmt.Sprintf("unexpected buffer len=%v", len(p))) } - panic(fmt.Sprintf("unexpected buffer len=%v", len(p))) } // dataBuffer is an io.ReadWriter backed by a list of data chunks. diff --git a/vendor/golang.org/x/net/http2/go111.go b/vendor/golang.org/x/net/http2/go111.go deleted file mode 100644 index 5bf62b032..000000000 --- a/vendor/golang.org/x/net/http2/go111.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.11 -// +build go1.11 - -package http2 - -import ( - "net/http/httptrace" - "net/textproto" -) - -func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { - return trace != nil && trace.WroteHeaderField != nil -} - -func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) { - if trace != nil && trace.WroteHeaderField != nil { - trace.WroteHeaderField(k, []string{v}) - } -} - -func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error { - if trace != nil { - return trace.Got1xxResponse - } - return nil -} diff --git a/vendor/golang.org/x/net/http2/go115.go b/vendor/golang.org/x/net/http2/go115.go deleted file mode 100644 index 908af1ab9..000000000 --- a/vendor/golang.org/x/net/http2/go115.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.15 -// +build go1.15 - -package http2 - -import ( - "context" - "crypto/tls" -) - -// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS -// connection. -func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) { - dialer := &tls.Dialer{ - Config: cfg, - } - cn, err := dialer.DialContext(ctx, network, addr) - if err != nil { - return nil, err - } - tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed - return tlsCn, nil -} diff --git a/vendor/golang.org/x/net/http2/go118.go b/vendor/golang.org/x/net/http2/go118.go deleted file mode 100644 index aca4b2b31..000000000 --- a/vendor/golang.org/x/net/http2/go118.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package http2 - -import ( - "crypto/tls" - "net" -) - -func tlsUnderlyingConn(tc *tls.Conn) net.Conn { - return tc.NetConn() -} diff --git a/vendor/golang.org/x/net/http2/not_go111.go b/vendor/golang.org/x/net/http2/not_go111.go deleted file mode 100644 index cc0baa819..000000000 --- a/vendor/golang.org/x/net/http2/not_go111.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.11 -// +build !go1.11 - -package http2 - -import ( - "net/http/httptrace" - "net/textproto" -) - -func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false } - -func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {} - -func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error { - return nil -} diff --git a/vendor/golang.org/x/net/http2/not_go115.go b/vendor/golang.org/x/net/http2/not_go115.go deleted file mode 100644 index e6c04cf7a..000000000 --- a/vendor/golang.org/x/net/http2/not_go115.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.15 -// +build !go1.15 - -package http2 - -import ( - "context" - "crypto/tls" -) - -// dialTLSWithContext opens a TLS connection. -func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) { - cn, err := tls.Dial(network, addr, cfg) - if err != nil { - return nil, err - } - if err := cn.Handshake(); err != nil { - return nil, err - } - if cfg.InsecureSkipVerify { - return cn, nil - } - if err := cn.VerifyHostname(cfg.ServerName); err != nil { - return nil, err - } - return cn, nil -} diff --git a/vendor/golang.org/x/net/http2/not_go118.go b/vendor/golang.org/x/net/http2/not_go118.go deleted file mode 100644 index eab532c96..000000000 --- a/vendor/golang.org/x/net/http2/not_go118.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package http2 - -import ( - "crypto/tls" - "net" -) - -func tlsUnderlyingConn(tc *tls.Conn) net.Conn { - return nil -} diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index 02c88b6b3..ae94c6408 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -2549,7 +2549,6 @@ type responseWriterState struct { wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. sentHeader bool // have we sent the header frame? handlerDone bool // handler has finished - dirty bool // a Write failed; don't reuse this responseWriterState sentContentLen int64 // non-zero if handler set a Content-Length header wroteBytes int64 @@ -2669,7 +2668,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { date: date, }) if err != nil { - rws.dirty = true return 0, err } if endStream { @@ -2690,7 +2688,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { if len(p) > 0 || endStream { // only send a 0 byte DATA frame if we're ending the stream. if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { - rws.dirty = true return 0, err } } @@ -2702,9 +2699,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { trailers: rws.trailers, endStream: true, }) - if err != nil { - rws.dirty = true - } return len(p), err } return len(p), nil @@ -2920,14 +2914,12 @@ func (rws *responseWriterState) writeHeader(code int) { h.Del("Transfer-Encoding") } - if rws.conn.writeHeaders(rws.stream, &writeResHeaders{ + rws.conn.writeHeaders(rws.stream, &writeResHeaders{ streamID: rws.stream.id, httpResCode: code, h: h, endStream: rws.handlerDone && !rws.hasTrailers(), - }) != nil { - rws.dirty = true - } + }) return } @@ -2992,19 +2984,10 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int, func (w *responseWriter) handlerDone() { rws := w.rws - dirty := rws.dirty rws.handlerDone = true w.Flush() w.rws = nil - if !dirty { - // Only recycle the pool if all prior Write calls to - // the serverConn goroutine completed successfully. If - // they returned earlier due to resets from the peer - // there might still be write goroutines outstanding - // from the serverConn referencing the rws memory. See - // issue 20704. - responseWriterStatePool.Put(rws) - } + responseWriterStatePool.Put(rws) } // Push errors. @@ -3187,6 +3170,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) { panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err)) } + sc.curHandlers++ go sc.runHandler(rw, req, sc.handler.ServeHTTP) return promisedID, nil } diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index 4515b22c4..df578b86c 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -1018,7 +1018,7 @@ func (cc *ClientConn) forceCloseConn() { if !ok { return } - if nc := tlsUnderlyingConn(tc); nc != nil { + if nc := tc.NetConn(); nc != nil { nc.Close() } } @@ -3201,3 +3201,34 @@ func traceFirstResponseByte(trace *httptrace.ClientTrace) { trace.GotFirstResponseByte() } } + +func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { + return trace != nil && trace.WroteHeaderField != nil +} + +func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) { + if trace != nil && trace.WroteHeaderField != nil { + trace.WroteHeaderField(k, []string{v}) + } +} + +func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error { + if trace != nil { + return trace.Got1xxResponse + } + return nil +} + +// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS +// connection. +func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) { + dialer := &tls.Dialer{ + Config: cfg, + } + cn, err := dialer.DialContext(ctx, network, addr) + if err != nil { + return nil, err + } + tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed + return tlsCn, nil +} diff --git a/vendor/golang.org/x/net/idna/go118.go b/vendor/golang.org/x/net/idna/go118.go index c5c4338db..712f1ad83 100644 --- a/vendor/golang.org/x/net/idna/go118.go +++ b/vendor/golang.org/x/net/idna/go118.go @@ -5,7 +5,6 @@ // license that can be found in the LICENSE file. //go:build go1.18 -// +build go1.18 package idna diff --git a/vendor/golang.org/x/net/idna/idna10.0.0.go b/vendor/golang.org/x/net/idna/idna10.0.0.go index 64ccf85fe..7b3717884 100644 --- a/vendor/golang.org/x/net/idna/idna10.0.0.go +++ b/vendor/golang.org/x/net/idna/idna10.0.0.go @@ -5,7 +5,6 @@ // license that can be found in the LICENSE file. //go:build go1.10 -// +build go1.10 // Package idna implements IDNA2008 using the compatibility processing // defined by UTS (Unicode Technical Standard) #46, which defines a standard to diff --git a/vendor/golang.org/x/net/idna/idna9.0.0.go b/vendor/golang.org/x/net/idna/idna9.0.0.go index ee1698cef..cc6a892a4 100644 --- a/vendor/golang.org/x/net/idna/idna9.0.0.go +++ b/vendor/golang.org/x/net/idna/idna9.0.0.go @@ -5,7 +5,6 @@ // license that can be found in the LICENSE file. //go:build !go1.10 -// +build !go1.10 // Package idna implements IDNA2008 using the compatibility processing // defined by UTS (Unicode Technical Standard) #46, which defines a standard to diff --git a/vendor/golang.org/x/net/idna/pre_go118.go b/vendor/golang.org/x/net/idna/pre_go118.go index 3aaccab1c..40e74bb3d 100644 --- a/vendor/golang.org/x/net/idna/pre_go118.go +++ b/vendor/golang.org/x/net/idna/pre_go118.go @@ -5,7 +5,6 @@ // license that can be found in the LICENSE file. //go:build !go1.18 -// +build !go1.18 package idna diff --git a/vendor/golang.org/x/net/idna/tables10.0.0.go b/vendor/golang.org/x/net/idna/tables10.0.0.go index d1d62ef45..c6c2bf10a 100644 --- a/vendor/golang.org/x/net/idna/tables10.0.0.go +++ b/vendor/golang.org/x/net/idna/tables10.0.0.go @@ -1,7 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. //go:build go1.10 && !go1.13 -// +build go1.10,!go1.13 package idna diff --git a/vendor/golang.org/x/net/idna/tables11.0.0.go b/vendor/golang.org/x/net/idna/tables11.0.0.go index 167efba71..76789393c 100644 --- a/vendor/golang.org/x/net/idna/tables11.0.0.go +++ b/vendor/golang.org/x/net/idna/tables11.0.0.go @@ -1,7 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. //go:build go1.13 && !go1.14 -// +build go1.13,!go1.14 package idna diff --git a/vendor/golang.org/x/net/idna/tables12.0.0.go b/vendor/golang.org/x/net/idna/tables12.0.0.go index ab40f7bcc..0600cd2ae 100644 --- a/vendor/golang.org/x/net/idna/tables12.0.0.go +++ b/vendor/golang.org/x/net/idna/tables12.0.0.go @@ -1,7 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. //go:build go1.14 && !go1.16 -// +build go1.14,!go1.16 package idna diff --git a/vendor/golang.org/x/net/idna/tables13.0.0.go b/vendor/golang.org/x/net/idna/tables13.0.0.go index 66701eadf..2fb768ef6 100644 --- a/vendor/golang.org/x/net/idna/tables13.0.0.go +++ b/vendor/golang.org/x/net/idna/tables13.0.0.go @@ -1,7 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. //go:build go1.16 && !go1.21 -// +build go1.16,!go1.21 package idna diff --git a/vendor/golang.org/x/net/idna/tables15.0.0.go b/vendor/golang.org/x/net/idna/tables15.0.0.go index 40033778f..5ff05fe1a 100644 --- a/vendor/golang.org/x/net/idna/tables15.0.0.go +++ b/vendor/golang.org/x/net/idna/tables15.0.0.go @@ -1,7 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. //go:build go1.21 -// +build go1.21 package idna diff --git a/vendor/golang.org/x/net/idna/tables9.0.0.go b/vendor/golang.org/x/net/idna/tables9.0.0.go index 4074b5332..0f25e84ca 100644 --- a/vendor/golang.org/x/net/idna/tables9.0.0.go +++ b/vendor/golang.org/x/net/idna/tables9.0.0.go @@ -1,7 +1,6 @@ // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. //go:build !go1.10 -// +build !go1.10 package idna diff --git a/vendor/golang.org/x/net/idna/trie12.0.0.go b/vendor/golang.org/x/net/idna/trie12.0.0.go index bb63f904b..8a75b9667 100644 --- a/vendor/golang.org/x/net/idna/trie12.0.0.go +++ b/vendor/golang.org/x/net/idna/trie12.0.0.go @@ -5,7 +5,6 @@ // license that can be found in the LICENSE file. //go:build !go1.16 -// +build !go1.16 package idna diff --git a/vendor/golang.org/x/net/idna/trie13.0.0.go b/vendor/golang.org/x/net/idna/trie13.0.0.go index 7d68a8dc1..fa45bb907 100644 --- a/vendor/golang.org/x/net/idna/trie13.0.0.go +++ b/vendor/golang.org/x/net/idna/trie13.0.0.go @@ -5,7 +5,6 @@ // license that can be found in the LICENSE file. //go:build go1.16 -// +build go1.16 package idna diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 6202638ba..c6492020e 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -248,6 +248,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -283,10 +284,6 @@ struct ltchars { #include #endif -#ifndef MSG_FASTOPEN -#define MSG_FASTOPEN 0x20000000 -#endif - #ifndef PTRACE_GETREGS #define PTRACE_GETREGS 0xc #endif @@ -295,14 +292,6 @@ struct ltchars { #define PTRACE_SETREGS 0xd #endif -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - -#ifndef SOL_SMC -#define SOL_SMC 286 -#endif - #ifdef SOL_BLUETOOTH // SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h // but it is already in bluetooth_linux.go @@ -319,10 +308,23 @@ struct ltchars { #undef TIPC_WAIT_FOREVER #define TIPC_WAIT_FOREVER 0xffffffff -// Copied from linux/l2tp.h -// Including linux/l2tp.h here causes conflicts between linux/in.h -// and netinet/in.h included via net/route.h above. -#define IPPROTO_L2TP 115 +// Copied from linux/netfilter/nf_nat.h +// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h +// and netinet/in.h. +#define NF_NAT_RANGE_MAP_IPS (1 << 0) +#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1) +#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2) +#define NF_NAT_RANGE_PERSISTENT (1 << 3) +#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4) +#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5) +#define NF_NAT_RANGE_NETMAP (1 << 6) +#define NF_NAT_RANGE_PROTO_RANDOM_ALL \ + (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY) +#define NF_NAT_RANGE_MASK \ + (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \ + NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \ + NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \ + NF_NAT_RANGE_NETMAP) // Copied from linux/hid.h. // Keep in sync with the size of the referenced fields. @@ -603,6 +605,9 @@ ccflags="$@" $2 ~ /^FSOPT_/ || $2 ~ /^WDIO[CFS]_/ || $2 ~ /^NFN/ || + $2 !~ /^NFT_META_IIFTYPE/ && + $2 ~ /^NFT_/ || + $2 ~ /^NF_NAT_/ || $2 ~ /^XDP_/ || $2 ~ /^RWF_/ || $2 ~ /^(HDIO|WIN|SMART)_/ || diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index c73cfe2f1..a5d3ff8df 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -2127,6 +2127,60 @@ const ( NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_ULOG = 0x4 NFS_SUPER_MAGIC = 0x6969 + NFT_CHAIN_FLAGS = 0x7 + NFT_CHAIN_MAXNAMELEN = 0x100 + NFT_CT_MAX = 0x17 + NFT_DATA_RESERVED_MASK = 0xffffff00 + NFT_DATA_VALUE_MAXLEN = 0x40 + NFT_EXTHDR_OP_MAX = 0x4 + NFT_FIB_RESULT_MAX = 0x3 + NFT_INNER_MASK = 0xf + NFT_LOGLEVEL_MAX = 0x8 + NFT_NAME_MAXLEN = 0x100 + NFT_NG_MAX = 0x1 + NFT_OBJECT_CONNLIMIT = 0x5 + NFT_OBJECT_COUNTER = 0x1 + NFT_OBJECT_CT_EXPECT = 0x9 + NFT_OBJECT_CT_HELPER = 0x3 + NFT_OBJECT_CT_TIMEOUT = 0x7 + NFT_OBJECT_LIMIT = 0x4 + NFT_OBJECT_MAX = 0xa + NFT_OBJECT_QUOTA = 0x2 + NFT_OBJECT_SECMARK = 0x8 + NFT_OBJECT_SYNPROXY = 0xa + NFT_OBJECT_TUNNEL = 0x6 + NFT_OBJECT_UNSPEC = 0x0 + NFT_OBJ_MAXNAMELEN = 0x100 + NFT_OSF_MAXGENRELEN = 0x10 + NFT_QUEUE_FLAG_BYPASS = 0x1 + NFT_QUEUE_FLAG_CPU_FANOUT = 0x2 + NFT_QUEUE_FLAG_MASK = 0x3 + NFT_REG32_COUNT = 0x10 + NFT_REG32_SIZE = 0x4 + NFT_REG_MAX = 0x4 + NFT_REG_SIZE = 0x10 + NFT_REJECT_ICMPX_MAX = 0x3 + NFT_RT_MAX = 0x4 + NFT_SECMARK_CTX_MAXLEN = 0x100 + NFT_SET_MAXNAMELEN = 0x100 + NFT_SOCKET_MAX = 0x3 + NFT_TABLE_F_MASK = 0x3 + NFT_TABLE_MAXNAMELEN = 0x100 + NFT_TRACETYPE_MAX = 0x3 + NFT_TUNNEL_F_MASK = 0x7 + NFT_TUNNEL_MAX = 0x1 + NFT_TUNNEL_MODE_MAX = 0x2 + NFT_USERDATA_MAXLEN = 0x100 + NFT_XFRM_KEY_MAX = 0x6 + NF_NAT_RANGE_MAP_IPS = 0x1 + NF_NAT_RANGE_MASK = 0x7f + NF_NAT_RANGE_NETMAP = 0x40 + NF_NAT_RANGE_PERSISTENT = 0x8 + NF_NAT_RANGE_PROTO_OFFSET = 0x20 + NF_NAT_RANGE_PROTO_RANDOM = 0x4 + NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14 + NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10 + NF_NAT_RANGE_PROTO_SPECIFIED = 0x2 NILFS_SUPER_MAGIC = 0x3434 NL0 = 0x0 NL1 = 0x100 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go index a1d061597..9dc42410b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go index 5b2a74097..0d3a0751c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index f6eda1344..c39f7776d 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go index 55df20ae9..57571d072 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go index 8c1155cbc..e62963e67 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go index 7cc80c58d..00831354c 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go index 0688737f4..79029ed58 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go @@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) { var libc_unveil_trampoline_addr uintptr //go:cgo_import_dynamic libc_unveil unveil "libc.so" - - diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 47dc57967..ffb8708cc 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -194,6 +194,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys SetEndOfFile(handle Handle) (err error) +//sys SetFileValidData(handle Handle, validDataLength int64) (err error) //sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 146a1f019..e8791c82c 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -342,6 +342,7 @@ var ( procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") + procSetFileValidData = modkernel32.NewProc("SetFileValidData") procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") procSetErrorMode = modkernel32.NewProc("SetErrorMode") procSetEvent = modkernel32.NewProc("SetEvent") @@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) { return } +func SetFileValidData(handle Handle, validDataLength int64) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) if r1 == 0 { diff --git a/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go b/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go new file mode 100644 index 000000000..2ef36bbcf --- /dev/null +++ b/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go @@ -0,0 +1,160 @@ +// Copyright 2022 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 protodelim marshals and unmarshals varint size-delimited messages. +package protodelim + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + + "google.golang.org/protobuf/encoding/protowire" + "google.golang.org/protobuf/internal/errors" + "google.golang.org/protobuf/proto" +) + +// MarshalOptions is a configurable varint size-delimited marshaler. +type MarshalOptions struct{ proto.MarshalOptions } + +// MarshalTo writes a varint size-delimited wire-format message to w. +// If w returns an error, MarshalTo returns it unchanged. +func (o MarshalOptions) MarshalTo(w io.Writer, m proto.Message) (int, error) { + msgBytes, err := o.MarshalOptions.Marshal(m) + if err != nil { + return 0, err + } + + sizeBytes := protowire.AppendVarint(nil, uint64(len(msgBytes))) + sizeWritten, err := w.Write(sizeBytes) + if err != nil { + return sizeWritten, err + } + msgWritten, err := w.Write(msgBytes) + if err != nil { + return sizeWritten + msgWritten, err + } + return sizeWritten + msgWritten, nil +} + +// MarshalTo writes a varint size-delimited wire-format message to w +// with the default options. +// +// See the documentation for [MarshalOptions.MarshalTo]. +func MarshalTo(w io.Writer, m proto.Message) (int, error) { + return MarshalOptions{}.MarshalTo(w, m) +} + +// UnmarshalOptions is a configurable varint size-delimited unmarshaler. +type UnmarshalOptions struct { + proto.UnmarshalOptions + + // MaxSize is the maximum size in wire-format bytes of a single message. + // Unmarshaling a message larger than MaxSize will return an error. + // A zero MaxSize will default to 4 MiB. + // Setting MaxSize to -1 disables the limit. + MaxSize int64 +} + +const defaultMaxSize = 4 << 20 // 4 MiB, corresponds to the default gRPC max request/response size + +// SizeTooLargeError is an error that is returned when the unmarshaler encounters a message size +// that is larger than its configured [UnmarshalOptions.MaxSize]. +type SizeTooLargeError struct { + // Size is the varint size of the message encountered + // that was larger than the provided MaxSize. + Size uint64 + + // MaxSize is the MaxSize limit configured in UnmarshalOptions, which Size exceeded. + MaxSize uint64 +} + +func (e *SizeTooLargeError) Error() string { + return fmt.Sprintf("message size %d exceeded unmarshaler's maximum configured size %d", e.Size, e.MaxSize) +} + +// Reader is the interface expected by [UnmarshalFrom]. +// It is implemented by *[bufio.Reader]. +type Reader interface { + io.Reader + io.ByteReader +} + +// UnmarshalFrom parses and consumes a varint size-delimited wire-format message +// from r. +// The provided message must be mutable (e.g., a non-nil pointer to a message). +// +// The error is [io.EOF] error only if no bytes are read. +// If an EOF happens after reading some but not all the bytes, +// UnmarshalFrom returns a non-io.EOF error. +// In particular if r returns a non-io.EOF error, UnmarshalFrom returns it unchanged, +// and if only a size is read with no subsequent message, [io.ErrUnexpectedEOF] is returned. +func (o UnmarshalOptions) UnmarshalFrom(r Reader, m proto.Message) error { + var sizeArr [binary.MaxVarintLen64]byte + sizeBuf := sizeArr[:0] + for i := range sizeArr { + b, err := r.ReadByte() + if err != nil { + // Immediate EOF is unexpected. + if err == io.EOF && i != 0 { + break + } + return err + } + sizeBuf = append(sizeBuf, b) + if b < 0x80 { + break + } + } + size, n := protowire.ConsumeVarint(sizeBuf) + if n < 0 { + return protowire.ParseError(n) + } + + maxSize := o.MaxSize + if maxSize == 0 { + maxSize = defaultMaxSize + } + if maxSize != -1 && size > uint64(maxSize) { + return errors.Wrap(&SizeTooLargeError{Size: size, MaxSize: uint64(maxSize)}, "") + } + + var b []byte + var err error + if br, ok := r.(*bufio.Reader); ok { + // Use the []byte from the bufio.Reader instead of having to allocate one. + // This reduces CPU usage and allocated bytes. + b, err = br.Peek(int(size)) + if err == nil { + defer br.Discard(int(size)) + } else { + b = nil + } + } + if b == nil { + b = make([]byte, size) + _, err = io.ReadFull(r, b) + } + + if err == io.EOF { + return io.ErrUnexpectedEOF + } + if err != nil { + return err + } + if err := o.Unmarshal(b, m); err != nil { + return err + } + return nil +} + +// UnmarshalFrom parses and consumes a varint size-delimited wire-format message +// from r with the default options. +// The provided message must be mutable (e.g., a non-nil pointer to a message). +// +// See the documentation for [UnmarshalOptions.UnmarshalFrom]. +func UnmarshalFrom(r Reader, m proto.Message) error { + return UnmarshalOptions{}.UnmarshalFrom(r, m) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b270754dc..8e0ccb05b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -291,7 +291,7 @@ github.com/golangci/revgrep # github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 ## explicit github.com/golangci/unconvert -# github.com/google/go-cmp v0.5.9 +# github.com/google/go-cmp v0.6.0 ## explicit; go 1.13 github.com/google/go-cmp/cmp github.com/google/go-cmp/cmp/internal/diff @@ -451,9 +451,6 @@ github.com/mattn/go-runewidth # github.com/mattn/goveralls v0.0.12 ## explicit; go 1.13 github.com/mattn/goveralls -# github.com/matttproud/golang_protobuf_extensions v1.0.1 -## explicit -github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/mbilski/exhaustivestruct v1.2.0 ## explicit; go 1.15 github.com/mbilski/exhaustivestruct/pkg/analyzer @@ -552,22 +549,23 @@ github.com/pmezard/go-difflib/difflib # github.com/polyfloyd/go-errorlint v1.1.0 ## explicit; go 1.13 github.com/polyfloyd/go-errorlint/errorlint -# github.com/prometheus/client_golang v1.14.0 -## explicit; go 1.17 +# github.com/prometheus/client_golang v1.19.0 +## explicit; go 1.20 github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp github.com/prometheus/client_golang/prometheus/testutil/promlint -# github.com/prometheus/client_model v0.3.0 -## explicit; go 1.9 +github.com/prometheus/client_golang/prometheus/testutil/promlint/validations +# github.com/prometheus/client_model v0.5.0 +## explicit; go 1.19 github.com/prometheus/client_model/go -# github.com/prometheus/common v0.37.0 -## explicit; go 1.16 +# github.com/prometheus/common v0.48.0 +## explicit; go 1.20 github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model -# github.com/prometheus/procfs v0.8.0 -## explicit; go 1.17 +# github.com/prometheus/procfs v0.12.0 +## explicit; go 1.19 github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util @@ -793,7 +791,7 @@ go.uber.org/zap/internal/bufferpool go.uber.org/zap/internal/color go.uber.org/zap/internal/exit go.uber.org/zap/zapcore -# golang.org/x/crypto v0.17.0 +# golang.org/x/crypto v0.18.0 ## explicit; go 1.18 golang.org/x/crypto/argon2 golang.org/x/crypto/blake2b @@ -811,8 +809,8 @@ golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.17.0 -## explicit; go 1.17 +# golang.org/x/net v0.20.0 +## explicit; go 1.18 golang.org/x/net/http/httpguts golang.org/x/net/http2 golang.org/x/net/http2/hpack @@ -824,7 +822,7 @@ golang.org/x/net/trace ## explicit; go 1.17 golang.org/x/sync/errgroup golang.org/x/sync/semaphore -# golang.org/x/sys v0.15.0 +# golang.org/x/sys v0.16.0 ## explicit; go 1.18 golang.org/x/sys/cpu golang.org/x/sys/execabs @@ -1004,6 +1002,7 @@ google.golang.org/grpc/cmd/protoc-gen-go-grpc google.golang.org/protobuf/cmd/protoc-gen-go google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo google.golang.org/protobuf/compiler/protogen +google.golang.org/protobuf/encoding/protodelim google.golang.org/protobuf/encoding/protojson google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/protowire From 3c0144e8e9e72839a0c4b6140c4b2df93d2d757e Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:35:40 +0200 Subject: [PATCH 18/31] gomod: Update github.com/rs/xid --- go.mod | 2 +- go.sum | 3 +- vendor/github.com/rs/xid/.golangci.yml | 5 + vendor/github.com/rs/xid/README.md | 17 ++- vendor/github.com/rs/xid/error.go | 11 ++ vendor/github.com/rs/xid/hostid_linux.go | 5 +- vendor/github.com/rs/xid/id.go | 128 ++++++++++++++--------- vendor/modules.txt | 4 +- 8 files changed, 114 insertions(+), 61 deletions(-) create mode 100644 vendor/github.com/rs/xid/.golangci.yml create mode 100644 vendor/github.com/rs/xid/error.go diff --git a/go.mod b/go.mod index 0b7c15963..e767c5de0 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 github.com/prometheus/client_golang v1.19.0 - github.com/rs/xid v1.2.1 + github.com/rs/xid v1.5.0 github.com/rs/zerolog v1.17.2 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 github.com/sony/gobreaker v0.4.1 diff --git a/go.sum b/go.sum index 5f9513da0..16fc2c4aa 100644 --- a/go.sum +++ b/go.sum @@ -561,8 +561,9 @@ github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.17.2 h1:RMRHFw2+wF7LO0QqtELQwo8hqSmqISyCJeFeAAuWcRo= github.com/rs/zerolog v1.17.2/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/vendor/github.com/rs/xid/.golangci.yml b/vendor/github.com/rs/xid/.golangci.yml new file mode 100644 index 000000000..7929600a9 --- /dev/null +++ b/vendor/github.com/rs/xid/.golangci.yml @@ -0,0 +1,5 @@ +run: + tests: false + +output: + sort-results: true diff --git a/vendor/github.com/rs/xid/README.md b/vendor/github.com/rs/xid/README.md index 1f886fd7c..974e67d29 100644 --- a/vendor/github.com/rs/xid/README.md +++ b/vendor/github.com/rs/xid/README.md @@ -2,9 +2,9 @@ [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/xid) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/xid/master/LICENSE) [![Build Status](https://travis-ci.org/rs/xid.svg?branch=master)](https://travis-ci.org/rs/xid) [![Coverage](http://gocover.io/_badge/github.com/rs/xid)](http://gocover.io/github.com/rs/xid) -Package xid is a globally unique id generator library, ready to be used safely directly in your server code. +Package xid is a globally unique id generator library, ready to safely be used directly in your server code. -Xid is using Mongo Object ID algorithm to generate globally unique ids with a different serialization (base64) to make it shorter when transported as a string: +Xid uses the Mongo Object ID algorithm to generate globally unique ids with a different serialization (base64) to make it shorter when transported as a string: https://docs.mongodb.org/manual/reference/object-id/ - 4-byte value representing the seconds since the Unix epoch, @@ -33,7 +33,7 @@ is required so it can be used directly in server's code. |-------------|-------------|----------------|---------------- | [UUID] | 16 bytes | 36 chars | configuration free, not sortable | [shortuuid] | 16 bytes | 22 chars | configuration free, not sortable -| [Snowflake] | 8 bytes | up to 20 chars | needs machin/DC configuration, needs central server, sortable +| [Snowflake] | 8 bytes | up to 20 chars | needs machine/DC configuration, needs central server, sortable | [MongoID] | 12 bytes | 24 chars | configuration free, sortable | xid | 12 bytes | 20 chars | configuration free, sortable @@ -57,7 +57,7 @@ Best used with [zerolog](https://github.com/rs/zerolog)'s Notes: -- Xid is dependent on the system time, a monotonic counter and so is not cryptographically secure. If unpredictability of IDs is important, you should not use Xids. It is worth noting that most of the other UUID like implementations are also not cryptographically secure. You shoud use libraries that rely on cryptographically secure sources (like /dev/urandom on unix, crypto/rand in golang), if you want a truly random ID generator. +- Xid is dependent on the system time, a monotonic counter and so is not cryptographically secure. If unpredictability of IDs is important, you should not use Xids. It is worth noting that most other UUID-like implementations are also not cryptographically secure. You should use libraries that rely on cryptographically secure sources (like /dev/urandom on unix, crypto/rand in golang), if you want a truly random ID generator. References: @@ -66,6 +66,13 @@ References: - https://blog.twitter.com/2010/announcing-snowflake - Python port by [Graham Abbott](https://github.com/graham): https://github.com/graham/python_xid - Scala port by [Egor Kolotaev](https://github.com/kolotaev): https://github.com/kolotaev/ride +- Rust port by [Jérôme Renard](https://github.com/jeromer/): https://github.com/jeromer/libxid +- Ruby port by [Valar](https://github.com/valarpirai/): https://github.com/valarpirai/ruby_xid +- Java port by [0xShamil](https://github.com/0xShamil/): https://github.com/0xShamil/java-xid +- Dart port by [Peter Bwire](https://github.com/pitabwire): https://pub.dev/packages/xid +- PostgreSQL port by [Rasmus Holm](https://github.com/crholm): https://github.com/modfin/pg-xid +- Swift port by [Uditha Atukorala](https://github.com/uditha-atukorala): https://github.com/uditha-atukorala/swift-xid +- C++ port by [Uditha Atukorala](https://github.com/uditha-atukorala): https://github.com/uditha-atukorala/libxid ## Install @@ -105,7 +112,7 @@ BenchmarkUUIDv4-2 1000000 1427 ns/op 64 B/op 2 allocs/op BenchmarkUUIDv4-4 1000000 1452 ns/op 64 B/op 2 allocs/op ``` -Note: UUIDv1 requires a global lock, hence the performence degrading as we add more CPUs. +Note: UUIDv1 requires a global lock, hence the performance degradation as we add more CPUs. ## Licenses diff --git a/vendor/github.com/rs/xid/error.go b/vendor/github.com/rs/xid/error.go new file mode 100644 index 000000000..ea2537493 --- /dev/null +++ b/vendor/github.com/rs/xid/error.go @@ -0,0 +1,11 @@ +package xid + +const ( + // ErrInvalidID is returned when trying to unmarshal an invalid ID. + ErrInvalidID strErr = "xid: invalid ID" +) + +// strErr allows declaring errors as constants. +type strErr string + +func (err strErr) Error() string { return string(err) } diff --git a/vendor/github.com/rs/xid/hostid_linux.go b/vendor/github.com/rs/xid/hostid_linux.go index 7d0c4a9ec..837b20436 100644 --- a/vendor/github.com/rs/xid/hostid_linux.go +++ b/vendor/github.com/rs/xid/hostid_linux.go @@ -5,6 +5,9 @@ package xid import "io/ioutil" func readPlatformMachineID() (string, error) { - b, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid") + b, err := ioutil.ReadFile("/etc/machine-id") + if err != nil || len(b) == 0 { + b, err = ioutil.ReadFile("/sys/class/dmi/id/product_uuid") + } return string(b), err } diff --git a/vendor/github.com/rs/xid/id.go b/vendor/github.com/rs/xid/id.go index 466faf262..fcd7a0413 100644 --- a/vendor/github.com/rs/xid/id.go +++ b/vendor/github.com/rs/xid/id.go @@ -43,11 +43,10 @@ package xid import ( "bytes" - "crypto/md5" + "crypto/sha256" "crypto/rand" "database/sql/driver" "encoding/binary" - "errors" "fmt" "hash/crc32" "io/ioutil" @@ -55,6 +54,7 @@ import ( "sort" "sync/atomic" "time" + "unsafe" ) // Code inspired from mgo/bson ObjectId @@ -72,16 +72,11 @@ const ( ) var ( - // ErrInvalidID is returned when trying to unmarshal an invalid ID - ErrInvalidID = errors.New("xid: invalid ID") - - // objectIDCounter is atomically incremented when generating a new ObjectId - // using NewObjectId() function. It's used as a counter part of an id. - // This id is initialized with a random value. + // objectIDCounter is atomically incremented when generating a new ObjectId. It's + // used as the counter part of an id. This id is initialized with a random value. objectIDCounter = randInt() - // machineId stores machine id generated once and used in subsequent calls - // to NewObjectId function. + // machineID is generated once and used in subsequent calls to the New* functions. machineID = readMachineID() // pid stores the current process id @@ -110,9 +105,9 @@ func init() { } } -// readMachineId generates machine id and puts it into the machineId global -// variable. If this function fails to get the hostname, it will cause -// a runtime error. +// readMachineID generates a machine ID, derived from a platform-specific machine ID +// value, or else the machine's hostname, or else a randomly-generated number. +// It panics if all of these methods fail. func readMachineID() []byte { id := make([]byte, 3) hid, err := readPlatformMachineID() @@ -120,7 +115,7 @@ func readMachineID() []byte { hid, err = os.Hostname() } if err == nil && len(hid) != 0 { - hw := md5.New() + hw := sha256.New() hw.Write([]byte(hid)) copy(id, hw.Sum(nil)) } else { @@ -151,7 +146,7 @@ func NewWithTime(t time.Time) ID { var id ID // Timestamp, 4 bytes, big endian binary.BigEndian.PutUint32(id[:], uint32(t.Unix())) - // Machine, first 3 bytes of md5(hostname) + // Machine ID, 3 bytes id[4] = machineID[0] id[5] = machineID[1] id[6] = machineID[2] @@ -177,7 +172,13 @@ func FromString(id string) (ID, error) { func (id ID) String() string { text := make([]byte, encodedLen) encode(text, id[:]) - return string(text) + return *(*string)(unsafe.Pointer(&text)) +} + +// Encode encodes the id using base32 encoding, writing 20 bytes to dst and return it. +func (id ID) Encode(dst []byte) []byte { + encode(dst, id[:]) + return dst } // MarshalText implements encoding/text TextMarshaler interface @@ -192,32 +193,37 @@ func (id ID) MarshalJSON() ([]byte, error) { if id.IsNil() { return []byte("null"), nil } - text, err := id.MarshalText() - return []byte(`"` + string(text) + `"`), err + text := make([]byte, encodedLen+2) + encode(text[1:encodedLen+1], id[:]) + text[0], text[encodedLen+1] = '"', '"' + return text, nil } // encode by unrolling the stdlib base32 algorithm + removing all safe checks func encode(dst, id []byte) { - dst[0] = encoding[id[0]>>3] - dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F] - dst[2] = encoding[(id[1]>>1)&0x1F] - dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F] - dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F] - dst[5] = encoding[(id[3]>>2)&0x1F] - dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F] - dst[7] = encoding[id[4]&0x1F] - dst[8] = encoding[id[5]>>3] - dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F] - dst[10] = encoding[(id[6]>>1)&0x1F] - dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F] - dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F] - dst[13] = encoding[(id[8]>>2)&0x1F] - dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F] - dst[15] = encoding[id[9]&0x1F] - dst[16] = encoding[id[10]>>3] - dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] - dst[18] = encoding[(id[11]>>1)&0x1F] + _ = dst[19] + _ = id[11] + dst[19] = encoding[(id[11]<<4)&0x1F] + dst[18] = encoding[(id[11]>>1)&0x1F] + dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] + dst[16] = encoding[id[10]>>3] + dst[15] = encoding[id[9]&0x1F] + dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F] + dst[13] = encoding[(id[8]>>2)&0x1F] + dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F] + dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F] + dst[10] = encoding[(id[6]>>1)&0x1F] + dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F] + dst[8] = encoding[id[5]>>3] + dst[7] = encoding[id[4]&0x1F] + dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F] + dst[5] = encoding[(id[3]>>2)&0x1F] + dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F] + dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F] + dst[2] = encoding[(id[1]>>1)&0x1F] + dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F] + dst[0] = encoding[id[0]>>3] } // UnmarshalText implements encoding/text TextUnmarshaler interface @@ -230,7 +236,10 @@ func (id *ID) UnmarshalText(text []byte) error { return ErrInvalidID } } - decode(id, text) + if !decode(id, text) { + *id = nilID + return ErrInvalidID + } return nil } @@ -241,23 +250,35 @@ func (id *ID) UnmarshalJSON(b []byte) error { *id = nilID return nil } + // Check the slice length to prevent panic on passing it to UnmarshalText() + if len(b) < 2 { + return ErrInvalidID + } return id.UnmarshalText(b[1 : len(b)-1]) } -// decode by unrolling the stdlib base32 algorithm + removing all safe checks -func decode(id *ID, src []byte) { - id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 - id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 - id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 - id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3 - id[4] = dec[src[6]]<<5 | dec[src[7]] - id[5] = dec[src[8]]<<3 | dec[src[9]]>>2 - id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4 - id[7] = dec[src[11]]<<4 | dec[src[12]]>>1 - id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3 - id[9] = dec[src[14]]<<5 | dec[src[15]] - id[10] = dec[src[16]]<<3 | dec[src[17]]>>2 +// decode by unrolling the stdlib base32 algorithm + customized safe check. +func decode(id *ID, src []byte) bool { + _ = src[19] + _ = id[11] + id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4 + // check the last byte + if encoding[(id[11]<<4)&0x1F] != src[19] { + return false + } + id[10] = dec[src[16]]<<3 | dec[src[17]]>>2 + id[9] = dec[src[14]]<<5 | dec[src[15]] + id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3 + id[7] = dec[src[11]]<<4 | dec[src[12]]>>1 + id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4 + id[5] = dec[src[8]]<<3 | dec[src[9]]>>2 + id[4] = dec[src[6]]<<5 | dec[src[7]] + id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3 + id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 + id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 + id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 + return true } // Time returns the timestamp part of the id. @@ -317,6 +338,11 @@ func (id ID) IsNil() bool { return id == nilID } +// Alias of IsNil +func (id ID) IsZero() bool { + return id.IsNil() +} + // NilID returns a zero value for `xid.ID`. func NilID() ID { return nilID diff --git a/vendor/modules.txt b/vendor/modules.txt index 8e0ccb05b..2516fe0bd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -597,8 +597,8 @@ github.com/quasilyte/regex/syntax # github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 ## explicit; go 1.17 github.com/quasilyte/stdinfo -# github.com/rs/xid v1.2.1 -## explicit +# github.com/rs/xid v1.5.0 +## explicit; go 1.12 github.com/rs/xid # github.com/rs/zerolog v1.17.2 ## explicit From acf9514f13026f2730820e36c7a7e4d7f2be35fd Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:36:14 +0200 Subject: [PATCH 19/31] gomod: Update github.com/rs/zerolog --- go.mod | 2 +- go.sum | 10 +- vendor/github.com/rs/zerolog/.travis.yml | 15 - vendor/github.com/rs/zerolog/README.md | 243 +++++++++++++-- vendor/github.com/rs/zerolog/array.go | 58 ++-- vendor/github.com/rs/zerolog/console.go | 160 +++++++--- vendor/github.com/rs/zerolog/context.go | 97 ++++-- vendor/github.com/rs/zerolog/ctx.go | 28 +- vendor/github.com/rs/zerolog/encoder_cbor.go | 10 + vendor/github.com/rs/zerolog/encoder_json.go | 19 ++ vendor/github.com/rs/zerolog/event.go | 147 ++++++++- vendor/github.com/rs/zerolog/example.jsonl | 7 + vendor/github.com/rs/zerolog/fields.go | 78 ++++- vendor/github.com/rs/zerolog/globals.go | 62 +++- .../rs/zerolog/internal/cbor/base.go | 10 +- .../rs/zerolog/internal/cbor/cbor.go | 8 +- .../rs/zerolog/internal/cbor/decode_stream.go | 66 +++- .../rs/zerolog/internal/cbor/string.go | 59 +++- .../rs/zerolog/internal/cbor/time.go | 12 +- .../rs/zerolog/internal/cbor/types.go | 74 +++-- .../rs/zerolog/internal/json/base.go | 15 +- .../rs/zerolog/internal/json/string.go | 38 ++- .../rs/zerolog/internal/json/time.go | 19 +- .../rs/zerolog/internal/json/types.go | 25 +- vendor/github.com/rs/zerolog/log.go | 155 ++++++--- vendor/github.com/rs/zerolog/log/log.go | 5 +- vendor/github.com/rs/zerolog/pretty.png | Bin 144694 -> 118839 bytes vendor/github.com/rs/zerolog/sampler.go | 2 +- vendor/github.com/rs/zerolog/syslog.go | 51 ++- vendor/github.com/rs/zerolog/writer.go | 294 ++++++++++++++++-- vendor/modules.txt | 4 +- 31 files changed, 1435 insertions(+), 338 deletions(-) delete mode 100644 vendor/github.com/rs/zerolog/.travis.yml create mode 100644 vendor/github.com/rs/zerolog/example.jsonl diff --git a/go.mod b/go.mod index e767c5de0..02326248e 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 github.com/prometheus/client_golang v1.19.0 github.com/rs/xid v1.5.0 - github.com/rs/zerolog v1.17.2 + github.com/rs/zerolog v1.32.0 github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 github.com/sony/gobreaker v0.4.1 github.com/spf13/cobra v1.6.1 diff --git a/go.sum b/go.sum index 16fc2c4aa..c8af3b13c 100644 --- a/go.sum +++ b/go.sum @@ -127,7 +127,7 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= @@ -222,6 +222,7 @@ github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80 github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -441,6 +442,7 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -564,8 +566,8 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.17.2 h1:RMRHFw2+wF7LO0QqtELQwo8hqSmqISyCJeFeAAuWcRo= -github.com/rs/zerolog v1.17.2/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= @@ -909,6 +911,7 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -955,7 +958,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw 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-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/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= diff --git a/vendor/github.com/rs/zerolog/.travis.yml b/vendor/github.com/rs/zerolog/.travis.yml deleted file mode 100644 index 70b67c963..000000000 --- a/vendor/github.com/rs/zerolog/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go -go: -- "1.7" -- "1.8" -- "1.9" -- "1.10" -- "1.11" -- "1.12" -- "master" -matrix: - allow_failures: - - go: "master" -script: - - go test -v -race -cpu=1,2,4 -bench . -benchmem ./... - - go test -v -tags binary_log -race -cpu=1,2,4 -bench . -benchmem ./... diff --git a/vendor/github.com/rs/zerolog/README.md b/vendor/github.com/rs/zerolog/README.md index 718681a94..afa615693 100644 --- a/vendor/github.com/rs/zerolog/README.md +++ b/vendor/github.com/rs/zerolog/README.md @@ -1,6 +1,6 @@ # Zero Allocation JSON Logger -[![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/zerolog) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/zerolog/master/LICENSE) [![Build Status](https://travis-ci.org/rs/zerolog.svg?branch=master)](https://travis-ci.org/rs/zerolog) [![Coverage](http://gocover.io/_badge/github.com/rs/zerolog)](http://gocover.io/github.com/rs/zerolog) +[![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/rs/zerolog) [![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/rs/zerolog/master/LICENSE) [![Build Status](https://github.com/rs/zerolog/actions/workflows/test.yml/badge.svg)](https://github.com/rs/zerolog/actions/workflows/test.yml) [![Go Coverage](https://github.com/rs/zerolog/wiki/coverage.svg)](https://raw.githack.com/wiki/rs/zerolog/coverage.html) The zerolog package provides a fast and simple logger dedicated to JSON output. @@ -18,20 +18,21 @@ Find out [who uses zerolog](https://github.com/rs/zerolog/wiki/Who-uses-zerolog) ## Features -* Blazing fast -* Low to zero allocation -* Level logging -* Sampling -* Hooks -* Contextual fields -* `context.Context` integration -* `net/http` helpers -* JSON and CBOR encoding formats -* Pretty logging for development +* [Blazing fast](#benchmarks) +* [Low to zero allocation](#benchmarks) +* [Leveled logging](#leveled-logging) +* [Sampling](#log-sampling) +* [Hooks](#hooks) +* [Contextual fields](#contextual-logging) +* [`context.Context` integration](#contextcontext-integration) +* [Integration with `net/http`](#integration-with-nethttp) +* [JSON and CBOR encoding formats](#binary-encoding) +* [Pretty logging for development](#pretty-logging) +* [Error Logging (with optional Stacktrace)](#error-logging) ## Installation -```go +```bash go get -u github.com/rs/zerolog/log ``` @@ -51,8 +52,6 @@ import ( func main() { // UNIX Time is faster and smaller than most timestamps - // If you set zerolog.TimeFieldFormat to an empty string, - // logs will write with UNIX time zerolog.TimeFieldFormat = zerolog.TimeFormatUnix log.Print("hello world") @@ -205,6 +204,80 @@ func main() { // Output: {"time":1494567715,"foo":"bar"} ``` +### Error Logging + +You can log errors using the `Err` method + +```go +package main + +import ( + "errors" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func main() { + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix + + err := errors.New("seems we have an error here") + log.Error().Err(err).Msg("") +} + +// Output: {"level":"error","error":"seems we have an error here","time":1609085256} +``` + +> The default field name for errors is `error`, you can change this by setting `zerolog.ErrorFieldName` to meet your needs. + +#### Error Logging with Stacktrace + +Using `github.com/pkg/errors`, you can add a formatted stacktrace to your errors. + +```go +package main + +import ( + "github.com/pkg/errors" + "github.com/rs/zerolog/pkgerrors" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func main() { + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix + zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack + + err := outer() + log.Error().Stack().Err(err).Msg("") +} + +func inner() error { + return errors.New("seems we have an error here") +} + +func middle() error { + err := inner() + if err != nil { + return err + } + return nil +} + +func outer() error { + err := middle() + if err != nil { + return err + } + return nil +} + +// Output: {"level":"error","stack":[{"func":"inner","line":"20","source":"errors.go"},{"func":"middle","line":"24","source":"errors.go"},{"func":"outer","line":"32","source":"errors.go"},{"func":"main","line":"15","source":"errors.go"},{"func":"main","line":"204","source":"proc.go"},{"func":"goexit","line":"1374","source":"asm_amd64.s"}],"error":"seems we have an error here","time":1609086683} +``` + +> zerolog.ErrorStackMarshaler must be set in order for the stack to output anything. + #### Logging Fatal Messages ```go @@ -235,6 +308,7 @@ func main() { > NOTE: Using `Msgf` generates one allocation even when the logger is disabled. + ### Create logger instance to manage different outputs ```go @@ -325,6 +399,8 @@ log.Logger = log.With().Str("foo", "bar").Logger() ### Add file and line number to log +Equivalent of `Llongfile`: + ```go log.Logger = log.With().Caller().Logger() log.Info().Msg("hello world") @@ -332,16 +408,35 @@ log.Info().Msg("hello world") // Output: {"level": "info", "message": "hello world", "caller": "/go/src/your_project/some_file:21"} ``` +Equivalent of `Lshortfile`: + +```go +zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string { + short := file + for i := len(file) - 1; i > 0; i-- { + if file[i] == '/' { + short = file[i+1:] + break + } + } + file = short + return file + ":" + strconv.Itoa(line) +} +log.Logger = log.With().Caller().Logger() +log.Info().Msg("hello world") + +// Output: {"level": "info", "message": "hello world", "caller": "some_file:21"} +``` ### Thread-safe, lock-free, non-blocking writer -If your writer might be slow or not thread-safe and you need your log producers to never get slowed down by a slow writer, you can use a `diode.Writer` as follow: +If your writer might be slow or not thread-safe and you need your log producers to never get slowed down by a slow writer, you can use a `diode.Writer` as follows: ```go wr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) { fmt.Printf("Logger Dropped %d messages", missed) }) -log := zerolog.New(w) +log := zerolog.New(wr) log.Print("test") ``` @@ -416,6 +511,58 @@ stdlog.Print("hello world") // Output: {"foo":"bar","message":"hello world"} ``` +### context.Context integration + +Go contexts are commonly passed throughout Go code, and this can help you pass +your Logger into places it might otherwise be hard to inject. The `Logger` +instance may be attached to Go context (`context.Context`) using +`Logger.WithContext(ctx)` and extracted from it using `zerolog.Ctx(ctx)`. +For example: + +```go +func f() { + logger := zerolog.New(os.Stdout) + ctx := context.Background() + + // Attach the Logger to the context.Context + ctx = logger.WithContext(ctx) + someFunc(ctx) +} + +func someFunc(ctx context.Context) { + // Get Logger from the go Context. if it's nil, then + // `zerolog.DefaultContextLogger` is returned, if + // `DefaultContextLogger` is nil, then a disabled logger is returned. + logger := zerolog.Ctx(ctx) + logger.Info().Msg("Hello") +} +``` + +A second form of `context.Context` integration allows you to pass the current +context.Context into the logged event, and retrieve it from hooks. This can be +useful to log trace and span IDs or other information stored in the go context, +and facilitates the unification of logging and tracing in some systems: + +```go +type TracingHook struct{} + +func (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) { + ctx := e.GetCtx() + spanId := getSpanIdFromContext(ctx) // as per your tracing framework + e.Str("span-id", spanId) +} + +func f() { + // Setup the logger + logger := zerolog.New(os.Stdout) + logger = logger.Hook(TracingHook{}) + + ctx := context.Background() + // Use the Ctx function to make the context available to the hook + logger.Info().Ctx(ctx).Msg("Hello") +} +``` + ### Integration with `net/http` The `github.com/rs/zerolog/hlog` package provides some helpers to integrate zerolog with `http.Handler`. @@ -435,11 +582,11 @@ c := alice.New() c = c.Append(hlog.NewHandler(log)) // Install some provided extra handler to set some request's context fields. -// Thanks to those handler, all our logs will come with some pre-populated fields. +// Thanks to that handler, all our logs will come with some prepopulated fields. c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) { hlog.FromRequest(r).Info(). Str("method", r.Method). - Str("url", r.URL.String()). + Stringer("url", r.URL). Int("status", status). Int("size", size). Dur("duration", duration). @@ -469,12 +616,31 @@ if err := http.ListenAndServe(":8080", nil); err != nil { } ``` +## Multiple Log Output +`zerolog.MultiLevelWriter` may be used to send the log message to multiple outputs. +In this example, we send the log message to both `os.Stdout` and the in-built ConsoleWriter. +```go +func main() { + consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} + + multi := zerolog.MultiLevelWriter(consoleWriter, os.Stdout) + + logger := zerolog.New(multi).With().Timestamp().Logger() + + logger.Info().Msg("Hello World!") +} + +// Output (Line 1: Console; Line 2: Stdout) +// 12:36PM INF Hello World! +// {"level":"info","time":"2019-11-07T12:36:38+03:00","message":"Hello World!"} +``` + ## Global Settings -Some settings can be changed and will by applied to all loggers: +Some settings can be changed and will be applied to all loggers: * `log.Logger`: You can set this value to customize the global logger (the one used by package level methods). -* `zerolog.SetGlobalLevel`: Can raise the minimum level of all loggers. Set this to `zerolog.Disabled` to disable logging altogether (quiet mode). +* `zerolog.SetGlobalLevel`: Can raise the minimum level of all loggers. Call this with `zerolog.Disabled` to disable logging altogether (quiet mode). * `zerolog.DisableSampling`: If argument is `true`, all sampled loggers will stop sampling and issue 100% of their log events. * `zerolog.TimestampFieldName`: Can be set to customize `Timestamp` field name. * `zerolog.LevelFieldName`: Can be set to customize level field name. @@ -497,16 +663,21 @@ Some settings can be changed and will by applied to all loggers: ### Advanced Fields -* `Err`: Takes an `error` and render it as a string using the `zerolog.ErrorFieldName` field name. -* `Timestamp`: Insert a timestamp field with `zerolog.TimestampFieldName` field name and formatted using `zerolog.TimeFieldFormat`. -* `Time`: Adds a field with the time formated with the `zerolog.TimeFieldFormat`. -* `Dur`: Adds a field with a `time.Duration`. +* `Err`: Takes an `error` and renders it as a string using the `zerolog.ErrorFieldName` field name. +* `Func`: Run a `func` only if the level is enabled. +* `Timestamp`: Inserts a timestamp field with `zerolog.TimestampFieldName` field name, formatted using `zerolog.TimeFieldFormat`. +* `Time`: Adds a field with time formatted with `zerolog.TimeFieldFormat`. +* `Dur`: Adds a field with `time.Duration`. * `Dict`: Adds a sub-key/value as a field of the event. +* `RawJSON`: Adds a field with an already encoded JSON (`[]byte`) +* `Hex`: Adds a field with value formatted as a hexadecimal string (`[]byte`) * `Interface`: Uses reflection to marshal the type. +Most fields are also available in the slice format (`Strs` for `[]string`, `Errs` for `[]error` etc.) + ## Binary Encoding -In addition to the default JSON encoding, `zerolog` can produce binary logs using [CBOR](http://cbor.io) encoding. The choice of encoding can be decided at compile time using the build tag `binary_log` as follows: +In addition to the default JSON encoding, `zerolog` can produce binary logs using [CBOR](https://cbor.io) encoding. The choice of encoding can be decided at compile time using the build tag `binary_log` as follows: ```bash go build -tags binary_log . @@ -518,10 +689,12 @@ with zerolog library is [CSD](https://github.com/toravir/csd/). ## Related Projects * [grpc-zerolog](https://github.com/cheapRoc/grpc-zerolog): Implementation of `grpclog.LoggerV2` interface using `zerolog` +* [overlog](https://github.com/Trendyol/overlog): Implementation of `Mapped Diagnostic Context` interface using `zerolog` +* [zerologr](https://github.com/go-logr/zerologr): Implementation of `logr.LogSink` interface using `zerolog` ## Benchmarks -See [logbench](http://hackemist.com/logbench/) for more comprehensive and up-to-date benchmarks. +See [logbench](http://bench.zerolog.io/) for more comprehensive and up-to-date benchmarks. All operations are allocation free (those numbers *include* JSON encoding): @@ -582,6 +755,8 @@ Log a static string, without any context or `printf`-style templating: ## Caveats +### Field duplication + Note that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON: ```go @@ -593,3 +768,19 @@ logger.Info(). ``` In this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt. + +### Concurrency safety + +Be careful when calling UpdateContext. It is not concurrency safe. Use the With method to create a child logger: + +```go +func handler(w http.ResponseWriter, r *http.Request) { + // Create a child logger for concurrency safety + logger := log.Logger.With().Logger() + + // Add context fields, for example User-Agent from HTTP headers + logger.UpdateContext(func(c zerolog.Context) zerolog.Context { + ... + }) +} +``` diff --git a/vendor/github.com/rs/zerolog/array.go b/vendor/github.com/rs/zerolog/array.go index d88c49762..99612ee9f 100644 --- a/vendor/github.com/rs/zerolog/array.go +++ b/vendor/github.com/rs/zerolog/array.go @@ -49,7 +49,7 @@ func (*Array) MarshalZerologArray(*Array) { func (a *Array) write(dst []byte) []byte { dst = enc.AppendArrayStart(dst) if len(a.buf) > 0 { - dst = append(append(dst, a.buf...)) + dst = append(dst, a.buf...) } dst = enc.AppendArrayEnd(dst) putArray(a) @@ -57,7 +57,7 @@ func (a *Array) write(dst []byte) []byte { } // Object marshals an object that implement the LogObjectMarshaler -// interface and append append it to the array. +// interface and appends it to the array. func (a *Array) Object(obj LogObjectMarshaler) *Array { e := Dict() obj.MarshalZerologObject(e) @@ -67,19 +67,19 @@ func (a *Array) Object(obj LogObjectMarshaler) *Array { return a } -// Str append append the val as a string to the array. +// Str appends the val as a string to the array. func (a *Array) Str(val string) *Array { a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), val) return a } -// Bytes append append the val as a string to the array. +// Bytes appends the val as a string to the array. func (a *Array) Bytes(val []byte) *Array { a.buf = enc.AppendBytes(enc.AppendArrayDelim(a.buf), val) return a } -// Hex append append the val as a hex string to the array. +// Hex appends the val as a hex string to the array. func (a *Array) Hex(val []byte) *Array { a.buf = enc.AppendHex(enc.AppendArrayDelim(a.buf), val) return a @@ -93,8 +93,7 @@ func (a *Array) RawJSON(val []byte) *Array { // Err serializes and appends the err to the array. func (a *Array) Err(err error) *Array { - marshaled := ErrorMarshalFunc(err) - switch m := marshaled.(type) { + switch m := ErrorMarshalFunc(err).(type) { case LogObjectMarshaler: e := newEvent(nil, 0) e.buf = e.buf[:0] @@ -102,7 +101,11 @@ func (a *Array) Err(err error) *Array { a.buf = append(enc.AppendArrayDelim(a.buf), e.buf...) putEvent(e) case error: - a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m.Error()) + if m == nil || isNilValue(m) { + a.buf = enc.AppendNil(enc.AppendArrayDelim(a.buf)) + } else { + a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m.Error()) + } case string: a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m) default: @@ -112,97 +115,97 @@ func (a *Array) Err(err error) *Array { return a } -// Bool append append the val as a bool to the array. +// Bool appends the val as a bool to the array. func (a *Array) Bool(b bool) *Array { a.buf = enc.AppendBool(enc.AppendArrayDelim(a.buf), b) return a } -// Int append append i as a int to the array. +// Int appends i as a int to the array. func (a *Array) Int(i int) *Array { a.buf = enc.AppendInt(enc.AppendArrayDelim(a.buf), i) return a } -// Int8 append append i as a int8 to the array. +// Int8 appends i as a int8 to the array. func (a *Array) Int8(i int8) *Array { a.buf = enc.AppendInt8(enc.AppendArrayDelim(a.buf), i) return a } -// Int16 append append i as a int16 to the array. +// Int16 appends i as a int16 to the array. func (a *Array) Int16(i int16) *Array { a.buf = enc.AppendInt16(enc.AppendArrayDelim(a.buf), i) return a } -// Int32 append append i as a int32 to the array. +// Int32 appends i as a int32 to the array. func (a *Array) Int32(i int32) *Array { a.buf = enc.AppendInt32(enc.AppendArrayDelim(a.buf), i) return a } -// Int64 append append i as a int64 to the array. +// Int64 appends i as a int64 to the array. func (a *Array) Int64(i int64) *Array { a.buf = enc.AppendInt64(enc.AppendArrayDelim(a.buf), i) return a } -// Uint append append i as a uint to the array. +// Uint appends i as a uint to the array. func (a *Array) Uint(i uint) *Array { a.buf = enc.AppendUint(enc.AppendArrayDelim(a.buf), i) return a } -// Uint8 append append i as a uint8 to the array. +// Uint8 appends i as a uint8 to the array. func (a *Array) Uint8(i uint8) *Array { a.buf = enc.AppendUint8(enc.AppendArrayDelim(a.buf), i) return a } -// Uint16 append append i as a uint16 to the array. +// Uint16 appends i as a uint16 to the array. func (a *Array) Uint16(i uint16) *Array { a.buf = enc.AppendUint16(enc.AppendArrayDelim(a.buf), i) return a } -// Uint32 append append i as a uint32 to the array. +// Uint32 appends i as a uint32 to the array. func (a *Array) Uint32(i uint32) *Array { a.buf = enc.AppendUint32(enc.AppendArrayDelim(a.buf), i) return a } -// Uint64 append append i as a uint64 to the array. +// Uint64 appends i as a uint64 to the array. func (a *Array) Uint64(i uint64) *Array { a.buf = enc.AppendUint64(enc.AppendArrayDelim(a.buf), i) return a } -// Float32 append append f as a float32 to the array. +// Float32 appends f as a float32 to the array. func (a *Array) Float32(f float32) *Array { a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f) return a } -// Float64 append append f as a float64 to the array. +// Float64 appends f as a float64 to the array. func (a *Array) Float64(f float64) *Array { a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f) return a } -// Time append append t formated as string using zerolog.TimeFieldFormat. +// Time appends t formatted as string using zerolog.TimeFieldFormat. func (a *Array) Time(t time.Time) *Array { a.buf = enc.AppendTime(enc.AppendArrayDelim(a.buf), t, TimeFieldFormat) return a } -// Dur append append d to the array. +// Dur appends d to the array. func (a *Array) Dur(d time.Duration) *Array { a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger) return a } -// Interface append append i marshaled using reflection. +// Interface appends i marshaled using reflection. func (a *Array) Interface(i interface{}) *Array { if obj, ok := i.(LogObjectMarshaler); ok { return a.Object(obj) @@ -228,3 +231,10 @@ func (a *Array) MACAddr(ha net.HardwareAddr) *Array { a.buf = enc.AppendMACAddr(enc.AppendArrayDelim(a.buf), ha) return a } + +// Dict adds the dict Event to the array +func (a *Array) Dict(dict *Event) *Array { + dict.buf = enc.AppendEndMarker(dict.buf) + a.buf = append(enc.AppendArrayDelim(a.buf), dict.buf...) + return a +} diff --git a/vendor/github.com/rs/zerolog/console.go b/vendor/github.com/rs/zerolog/console.go index 75f6e4575..cc6d623e2 100644 --- a/vendor/github.com/rs/zerolog/console.go +++ b/vendor/github.com/rs/zerolog/console.go @@ -6,11 +6,14 @@ import ( "fmt" "io" "os" + "path/filepath" "sort" "strconv" "strings" "sync" "time" + + "github.com/mattn/go-colorable" ) const ( @@ -57,6 +60,12 @@ type ConsoleWriter struct { // PartsOrder defines the order of parts in output. PartsOrder []string + // PartsExclude defines parts to not display in output. + PartsExclude []string + + // FieldsExclude defines contextual fields to not display in output. + FieldsExclude []string + FormatTimestamp Formatter FormatLevel Formatter FormatCaller Formatter @@ -65,6 +74,10 @@ type ConsoleWriter struct { FormatFieldValue Formatter FormatErrFieldName Formatter FormatErrFieldValue Formatter + + FormatExtra func(map[string]interface{}, *bytes.Buffer) error + + FormatPrepare func(map[string]interface{}) error } // NewConsoleWriter creates and initializes a new ConsoleWriter. @@ -79,11 +92,21 @@ func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter { opt(&w) } + // Fix color on Windows + if w.Out == os.Stdout || w.Out == os.Stderr { + w.Out = colorable.NewColorable(w.Out.(*os.File)) + } + return w } // Write transforms the JSON input with formatters and appends to w.Out. func (w ConsoleWriter) Write(p []byte) (n int, err error) { + // Fix color on Windows + if w.Out == os.Stdout || w.Out == os.Stderr { + w.Out = colorable.NewColorable(w.Out.(*os.File)) + } + if w.PartsOrder == nil { w.PartsOrder = consoleDefaultPartsOrder() } @@ -103,24 +126,59 @@ func (w ConsoleWriter) Write(p []byte) (n int, err error) { return n, fmt.Errorf("cannot decode event: %s", err) } + if w.FormatPrepare != nil { + err = w.FormatPrepare(evt) + if err != nil { + return n, err + } + } + for _, p := range w.PartsOrder { w.writePart(buf, evt, p) } w.writeFields(evt, buf) + if w.FormatExtra != nil { + err = w.FormatExtra(evt, buf) + if err != nil { + return n, err + } + } + err = buf.WriteByte('\n') if err != nil { return n, err } + _, err = buf.WriteTo(w.Out) return len(p), err } +// Call the underlying writer's Close method if it is an io.Closer. Otherwise +// does nothing. +func (w ConsoleWriter) Close() error { + if closer, ok := w.Out.(io.Closer); ok { + return closer.Close() + } + return nil +} + // writeFields appends formatted key-value pairs to buf. func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer) { var fields = make([]string, 0, len(evt)) for field := range evt { + var isExcluded bool + for _, excluded := range w.FieldsExclude { + if field == excluded { + isExcluded = true + break + } + } + if isExcluded { + continue + } + switch field { case LevelFieldName, TimestampFieldName, MessageFieldName, CallerFieldName: continue @@ -129,7 +187,8 @@ func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer } sort.Strings(fields) - if len(fields) > 0 { + // Write space only if something has already been written to the buffer, and if there are fields. + if buf.Len() > 0 && len(fields) > 0 { buf.WriteByte(' ') } @@ -190,7 +249,7 @@ func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer case json.Number: buf.WriteString(fv(fValue)) default: - b, err := json.Marshal(fValue) + b, err := InterfaceMarshalFunc(fValue) if err != nil { fmt.Fprintf(buf, colorize("[error: %v]", colorRed, w.NoColor), err) } else { @@ -208,6 +267,14 @@ func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{}, p string) { var f Formatter + if w.PartsExclude != nil && len(w.PartsExclude) > 0 { + for _, exclude := range w.PartsExclude { + if exclude == p { + return + } + } + } + switch p { case LevelFieldName: if w.FormatLevel == nil { @@ -223,7 +290,7 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{}, } case MessageFieldName: if w.FormatMessage == nil { - f = consoleDefaultFormatMessage + f = consoleDefaultFormatMessage(w.NoColor, evt[LevelFieldName]) } else { f = w.FormatMessage } @@ -244,10 +311,10 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{}, var s = f(evt[p]) if len(s) > 0 { - buf.WriteString(s) - if p != w.PartsOrder[len(w.PartsOrder)-1] { // Skip space for last part - buf.WriteByte(' ') + if buf.Len() > 0 { + buf.WriteByte(' ') // Write space only if not the first part } + buf.WriteString(s) } } @@ -261,8 +328,13 @@ func needsQuote(s string) bool { return false } -// colorize returns the string s wrapped in ANSI code c, unless disabled is true. +// colorize returns the string s wrapped in ANSI code c, unless disabled is true or c is 0. func colorize(s interface{}, c int, disabled bool) string { + e := os.Getenv("NO_COLOR") + if e != "" || c == 0 { + disabled = true + } + if disabled { return fmt.Sprintf("%s", s) } @@ -288,23 +360,31 @@ func consoleDefaultFormatTimestamp(timeFormat string, noColor bool) Formatter { t := "" switch tt := i.(type) { case string: - ts, err := time.Parse(TimeFieldFormat, tt) + ts, err := time.ParseInLocation(TimeFieldFormat, tt, time.Local) if err != nil { t = tt } else { - t = ts.Format(timeFormat) + t = ts.Local().Format(timeFormat) } case json.Number: i, err := tt.Int64() if err != nil { t = tt.String() } else { - var sec, nsec int64 = i, 0 - if TimeFieldFormat == TimeFormatUnixMs { - nsec = int64(time.Duration(i) * time.Millisecond) - sec = 0 + var sec, nsec int64 + + switch TimeFieldFormat { + case TimeFormatUnixNano: + sec, nsec = 0, i + case TimeFormatUnixMicro: + sec, nsec = 0, int64(time.Duration(i)*time.Microsecond) + case TimeFormatUnixMs: + sec, nsec = 0, int64(time.Duration(i)*time.Millisecond) + default: + sec, nsec = i, 0 } - ts := time.Unix(sec, nsec).UTC() + + ts := time.Unix(sec, nsec) t = ts.Format(timeFormat) } } @@ -316,27 +396,16 @@ func consoleDefaultFormatLevel(noColor bool) Formatter { return func(i interface{}) string { var l string if ll, ok := i.(string); ok { - switch ll { - case "trace": - l = colorize("TRC", colorMagenta, noColor) - case "debug": - l = colorize("DBG", colorYellow, noColor) - case "info": - l = colorize("INF", colorGreen, noColor) - case "warn": - l = colorize("WRN", colorRed, noColor) - case "error": - l = colorize(colorize("ERR", colorRed, noColor), colorBold, noColor) - case "fatal": - l = colorize(colorize("FTL", colorRed, noColor), colorBold, noColor) - case "panic": - l = colorize(colorize("PNC", colorRed, noColor), colorBold, noColor) - default: - l = colorize("???", colorBold, noColor) + level, _ := ParseLevel(ll) + fl, ok := FormattedLevels[level] + if ok { + l = colorize(fl, LevelColors[level], noColor) + } else { + l = strings.ToUpper(ll)[0:3] } } else { if i == nil { - l = colorize("???", colorBold, noColor) + l = "???" } else { l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3] } @@ -352,10 +421,10 @@ func consoleDefaultFormatCaller(noColor bool) Formatter { c = cc } if len(c) > 0 { - cwd, err := os.Getwd() - if err == nil { - c = strings.TrimPrefix(c, cwd) - c = strings.TrimPrefix(c, "/") + if cwd, err := os.Getwd(); err == nil { + if rel, err := filepath.Rel(cwd, c); err == nil { + c = rel + } } c = colorize(c, colorBold, noColor) + colorize(" >", colorCyan, noColor) } @@ -363,11 +432,18 @@ func consoleDefaultFormatCaller(noColor bool) Formatter { } } -func consoleDefaultFormatMessage(i interface{}) string { - if i == nil { - return "" +func consoleDefaultFormatMessage(noColor bool, level interface{}) Formatter { + return func(i interface{}) string { + if i == nil || i == "" { + return "" + } + switch level { + case LevelInfoValue, LevelWarnValue, LevelErrorValue, LevelFatalValue, LevelPanicValue: + return colorize(fmt.Sprintf("%s", i), colorBold, noColor) + default: + return fmt.Sprintf("%s", i) + } } - return fmt.Sprintf("%s", i) } func consoleDefaultFormatFieldName(noColor bool) Formatter { @@ -382,12 +458,12 @@ func consoleDefaultFormatFieldValue(i interface{}) string { func consoleDefaultFormatErrFieldName(noColor bool) Formatter { return func(i interface{}) string { - return colorize(fmt.Sprintf("%s=", i), colorRed, noColor) + return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor) } } func consoleDefaultFormatErrFieldValue(noColor bool) Formatter { return func(i interface{}) string { - return colorize(fmt.Sprintf("%s", i), colorRed, noColor) + return colorize(colorize(fmt.Sprintf("%s", i), colorBold, noColor), colorRed, noColor) } } diff --git a/vendor/github.com/rs/zerolog/context.go b/vendor/github.com/rs/zerolog/context.go index 1815a0804..df352eb66 100644 --- a/vendor/github.com/rs/zerolog/context.go +++ b/vendor/github.com/rs/zerolog/context.go @@ -1,7 +1,9 @@ package zerolog import ( - "io/ioutil" + "context" + "fmt" + "io" "math" "net" "time" @@ -17,9 +19,11 @@ func (c Context) Logger() Logger { return c.l } -// Fields is a helper function to use a map to set fields using type assertion. -func (c Context) Fields(fields map[string]interface{}) Context { - c.l.context = appendFields(c.l.context, fields) +// Fields is a helper function to use a map or slice to set fields using type assertion. +// Only map[string]interface{} and []interface{} are accepted. []interface{} must +// alternate string keys and arbitrary values, and extraneous ones are ignored. +func (c Context) Fields(fields interface{}) Context { + c.l.context = appendFields(c.l.context, fields, c.l.stack) return c } @@ -53,7 +57,7 @@ func (c Context) Array(key string, arr LogArrayMarshaler) Context { // Object marshals an object that implement the LogObjectMarshaler interface. func (c Context) Object(key string, obj LogObjectMarshaler) Context { - e := newEvent(levelWriterAdapter{ioutil.Discard}, 0) + e := newEvent(LevelWriterAdapter{io.Discard}, 0) e.Object(key, obj) c.l.context = enc.AppendObjectData(c.l.context, e.buf) putEvent(e) @@ -62,7 +66,7 @@ func (c Context) Object(key string, obj LogObjectMarshaler) Context { // EmbedObject marshals and Embeds an object that implement the LogObjectMarshaler interface. func (c Context) EmbedObject(obj LogObjectMarshaler) Context { - e := newEvent(levelWriterAdapter{ioutil.Discard}, 0) + e := newEvent(LevelWriterAdapter{io.Discard}, 0) e.EmbedObject(obj) c.l.context = enc.AppendObjectData(c.l.context, e.buf) putEvent(e) @@ -81,6 +85,17 @@ func (c Context) Strs(key string, vals []string) Context { return c } +// Stringer adds the field key with val.String() (or null if val is nil) to the logger context. +func (c Context) Stringer(key string, val fmt.Stringer) Context { + if val != nil { + c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val.String()) + return c + } + + c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), nil) + return c +} + // Bytes adds the field key with val as a []byte to the logger context. func (c Context) Bytes(key string, val []byte) Context { c.l.context = enc.AppendBytes(enc.AppendKey(c.l.context, key), val) @@ -104,14 +119,17 @@ func (c Context) RawJSON(key string, b []byte) Context { // AnErr adds the field key with serialized err to the logger context. func (c Context) AnErr(key string, err error) Context { - marshaled := ErrorMarshalFunc(err) - switch m := marshaled.(type) { + switch m := ErrorMarshalFunc(err).(type) { case nil: return c case LogObjectMarshaler: return c.Object(key, m) case error: - return c.Str(key, m.Error()) + if m == nil || isNilValue(m) { + return c + } else { + return c.Str(key, m.Error()) + } case string: return c.Str(key, m) default: @@ -124,12 +142,15 @@ func (c Context) AnErr(key string, err error) Context { func (c Context) Errs(key string, errs []error) Context { arr := Arr() for _, err := range errs { - marshaled := ErrorMarshalFunc(err) - switch m := marshaled.(type) { + switch m := ErrorMarshalFunc(err).(type) { case LogObjectMarshaler: arr = arr.Object(m) case error: - arr = arr.Str(m.Error()) + if m == nil || isNilValue(m) { + arr = arr.Interface(nil) + } else { + arr = arr.Str(m.Error()) + } case string: arr = arr.Str(m) default: @@ -142,9 +163,34 @@ func (c Context) Errs(key string, errs []error) Context { // Err adds the field "error" with serialized err to the logger context. func (c Context) Err(err error) Context { + if c.l.stack && ErrorStackMarshaler != nil { + switch m := ErrorStackMarshaler(err).(type) { + case nil: + case LogObjectMarshaler: + c = c.Object(ErrorStackFieldName, m) + case error: + if m != nil && !isNilValue(m) { + c = c.Str(ErrorStackFieldName, m.Error()) + } + case string: + c = c.Str(ErrorStackFieldName, m) + default: + c = c.Interface(ErrorStackFieldName, m) + } + } + return c.AnErr(ErrorFieldName, err) } +// Ctx adds the context.Context to the logger context. The context.Context is +// not rendered in the error message, but is made available for hooks to use. +// A typical use case is to extract tracing information from the +// context.Context. +func (c Context) Ctx(ctx context.Context) Context { + c.l.ctx = ctx + return c +} + // Bool adds the field key with val as a bool to the logger context. func (c Context) Bool(key string, b bool) Context { c.l.context = enc.AppendBool(enc.AppendKey(c.l.context, key), b) @@ -309,8 +355,9 @@ func (ts timestampHook) Run(e *Event, level Level, msg string) { var th = timestampHook{} -// Timestamp adds the current local time as UNIX timestamp to the logger context with the "time" key. +// Timestamp adds the current local time to the logger context with the "time" key, formatted using zerolog.TimeFieldFormat. // To customize the key name, change zerolog.TimestampFieldName. +// To customize the time format, change zerolog.TimeFieldFormat. // // NOTE: It won't dedupe the "time" key if the *Context has one already. func (c Context) Timestamp() Context { @@ -344,10 +391,24 @@ func (c Context) Durs(key string, d []time.Duration) Context { // Interface adds the field key with obj marshaled using reflection. func (c Context) Interface(key string, i interface{}) Context { + if obj, ok := i.(LogObjectMarshaler); ok { + return c.Object(key, obj) + } c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), i) return c } +// Type adds the field key with val's type using reflection. +func (c Context) Type(key string, val interface{}) Context { + c.l.context = enc.AppendType(enc.AppendKey(c.l.context, key), val) + return c +} + +// Any is a wrapper around Context.Interface. +func (c Context) Any(key string, i interface{}) Context { + return c.Interface(key, i) +} + type callerHook struct { callerSkipFrameCount int } @@ -388,17 +449,9 @@ func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context { return c } -type stackTraceHook struct{} - -func (sh stackTraceHook) Run(e *Event, level Level, msg string) { - e.Stack() -} - -var sh = stackTraceHook{} - // Stack enables stack trace printing for the error passed to Err(). func (c Context) Stack() Context { - c.l = c.l.Hook(sh) + c.l.stack = true return c } diff --git a/vendor/github.com/rs/zerolog/ctx.go b/vendor/github.com/rs/zerolog/ctx.go index ce18a32cb..60432d153 100644 --- a/vendor/github.com/rs/zerolog/ctx.go +++ b/vendor/github.com/rs/zerolog/ctx.go @@ -14,10 +14,15 @@ func init() { type ctxKey struct{} -// WithContext returns a copy of ctx with l associated. If an instance of Logger -// is already in the context, the context is not updated. +// WithContext returns a copy of ctx with the receiver attached. The Logger +// attached to the provided Context (if any) will not be effected. If the +// receiver's log level is Disabled it will only be attached to the returned +// Context if the provided Context has a previously attached Logger. If the +// provided Context has no attached Logger, a Disabled Logger will not be +// attached. // -// For instance, to add a field to an existing logger in the context, use this +// Note: to modify the existing Logger attached to a Context (instead of +// replacing it in a new Context), use UpdateContext with the following // notation: // // ctx := r.Context() @@ -25,24 +30,23 @@ type ctxKey struct{} // l.UpdateContext(func(c Context) Context { // return c.Str("bar", "baz") // }) -func (l *Logger) WithContext(ctx context.Context) context.Context { - if lp, ok := ctx.Value(ctxKey{}).(*Logger); ok { - if lp == l { - // Do not store same logger. - return ctx - } - } else if l.level == Disabled { +// +func (l Logger) WithContext(ctx context.Context) context.Context { + if _, ok := ctx.Value(ctxKey{}).(*Logger); !ok && l.level == Disabled { // Do not store disabled logger. return ctx } - return context.WithValue(ctx, ctxKey{}, l) + return context.WithValue(ctx, ctxKey{}, &l) } // Ctx returns the Logger associated with the ctx. If no logger -// is associated, a disabled logger is returned. +// is associated, DefaultContextLogger is returned, unless DefaultContextLogger +// is nil, in which case a disabled logger is returned. func Ctx(ctx context.Context) *Logger { if l, ok := ctx.Value(ctxKey{}).(*Logger); ok { return l + } else if l = DefaultContextLogger; l != nil { + return l } return disabledLogger } diff --git a/vendor/github.com/rs/zerolog/encoder_cbor.go b/vendor/github.com/rs/zerolog/encoder_cbor.go index f8d3fe9e7..36cb994b8 100644 --- a/vendor/github.com/rs/zerolog/encoder_cbor.go +++ b/vendor/github.com/rs/zerolog/encoder_cbor.go @@ -14,9 +14,19 @@ var ( enc = cbor.Encoder{} ) +func init() { + // using closure to reflect the changes at runtime. + cbor.JSONMarshalFunc = func(v interface{}) ([]byte, error) { + return InterfaceMarshalFunc(v) + } +} + func appendJSON(dst []byte, j []byte) []byte { return cbor.AppendEmbeddedJSON(dst, j) } +func appendCBOR(dst []byte, c []byte) []byte { + return cbor.AppendEmbeddedCBOR(dst, c) +} // decodeIfBinaryToString - converts a binary formatted log msg to a // JSON formatted String Log message. diff --git a/vendor/github.com/rs/zerolog/encoder_json.go b/vendor/github.com/rs/zerolog/encoder_json.go index fe580f5f6..6f96c68ad 100644 --- a/vendor/github.com/rs/zerolog/encoder_json.go +++ b/vendor/github.com/rs/zerolog/encoder_json.go @@ -6,6 +6,7 @@ package zerolog // JSON encoded byte stream. import ( + "encoding/base64" "github.com/rs/zerolog/internal/json" ) @@ -15,9 +16,27 @@ var ( enc = json.Encoder{} ) +func init() { + // using closure to reflect the changes at runtime. + json.JSONMarshalFunc = func(v interface{}) ([]byte, error) { + return InterfaceMarshalFunc(v) + } +} + func appendJSON(dst []byte, j []byte) []byte { return append(dst, j...) } +func appendCBOR(dst []byte, cbor []byte) []byte { + dst = append(dst, []byte("\"data:application/cbor;base64,")...) + l := len(dst) + enc := base64.StdEncoding + n := enc.EncodedLen(len(cbor)) + for i := 0; i < n; i++ { + dst = append(dst, '.') + } + enc.Encode(dst[l:], cbor) + return append(dst, '"') +} func decodeIfBinaryToString(in []byte) string { return string(in) diff --git a/vendor/github.com/rs/zerolog/event.go b/vendor/github.com/rs/zerolog/event.go index 1402835d0..5c949f8a7 100644 --- a/vendor/github.com/rs/zerolog/event.go +++ b/vendor/github.com/rs/zerolog/event.go @@ -1,6 +1,7 @@ package zerolog import ( + "context" "fmt" "net" "os" @@ -20,12 +21,14 @@ var eventPool = &sync.Pool{ // Event represents a log event. It is instanced by one of the level method of // Logger and finalized by the Msg or Msgf method. type Event struct { - buf []byte - w LevelWriter - level Level - done func(msg string) - stack bool // enable error stack trace - ch []Hook // hooks from context + buf []byte + w LevelWriter + level Level + done func(msg string) + stack bool // enable error stack trace + ch []Hook // hooks from context + skipFrame int // The number of additional frames to skip when printing the caller. + ctx context.Context // Optional Go context for event } func putEvent(e *Event) { @@ -61,6 +64,8 @@ func newEvent(w LevelWriter, level Level) *Event { e.buf = enc.AppendBeginMarker(e.buf) e.w = w e.level = level + e.stack = false + e.skipFrame = 0 return e } @@ -126,6 +131,13 @@ func (e *Event) Msgf(format string, v ...interface{}) { e.msg(fmt.Sprintf(format, v...)) } +func (e *Event) MsgFunc(createMsg func() string) { + if e == nil { + return + } + e.msg(createMsg()) +} + func (e *Event) msg(msg string) { for _, hook := range e.ch { hook.Run(e, e.level, msg) @@ -145,12 +157,14 @@ func (e *Event) msg(msg string) { } } -// Fields is a helper function to use a map to set fields using type assertion. -func (e *Event) Fields(fields map[string]interface{}) *Event { +// Fields is a helper function to use a map or slice to set fields using type assertion. +// Only map[string]interface{} and []interface{} are accepted. []interface{} must +// alternate string keys and arbitrary values, and extraneous ones are ignored. +func (e *Event) Fields(fields interface{}) *Event { if e == nil { return e } - e.buf = appendFields(e.buf, fields) + e.buf = appendFields(e.buf, fields, e.stack) return e } @@ -204,15 +218,32 @@ func (e *Event) Object(key string, obj LogObjectMarshaler) *Event { return e } e.buf = enc.AppendKey(e.buf, key) + if obj == nil { + e.buf = enc.AppendNil(e.buf) + + return e + } + e.appendObject(obj) return e } +// Func allows an anonymous func to run only if the event is enabled. +func (e *Event) Func(f func(e *Event)) *Event { + if e != nil && e.Enabled() { + f(e) + } + return e +} + // EmbedObject marshals an object that implement the LogObjectMarshaler interface. func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event { if e == nil { return e } + if obj == nil { + return e + } obj.MarshalZerologObject(e) return e } @@ -235,6 +266,27 @@ func (e *Event) Strs(key string, vals []string) *Event { return e } +// Stringer adds the field key with val.String() (or null if val is nil) +// to the *Event context. +func (e *Event) Stringer(key string, val fmt.Stringer) *Event { + if e == nil { + return e + } + e.buf = enc.AppendStringer(enc.AppendKey(e.buf, key), val) + return e +} + +// Stringers adds the field key with vals where each individual val +// is used as val.String() (or null if val is empty) to the *Event +// context. +func (e *Event) Stringers(key string, vals []fmt.Stringer) *Event { + if e == nil { + return e + } + e.buf = enc.AppendStringers(enc.AppendKey(e.buf, key), vals) + return e +} + // Bytes adds the field key with val as a string to the *Event context. // // Runes outside of normal ASCII ranges will be hex-encoded in the resulting @@ -268,6 +320,18 @@ func (e *Event) RawJSON(key string, b []byte) *Event { return e } +// RawCBOR adds already encoded CBOR to the log line under key. +// +// No sanity check is performed on b +// Note: The full featureset of CBOR is supported as data will not be mapped to json but stored as data-url +func (e *Event) RawCBOR(key string, b []byte) *Event { + if e == nil { + return e + } + e.buf = appendCBOR(enc.AppendKey(e.buf, key), b) + return e +} + // AnErr adds the field key with serialized err to the *Event context. // If err is nil, no field is added. func (e *Event) AnErr(key string, err error) *Event { @@ -280,7 +344,11 @@ func (e *Event) AnErr(key string, err error) *Event { case LogObjectMarshaler: return e.Object(key, m) case error: - return e.Str(key, m.Error()) + if m == nil || isNilValue(m) { + return e + } else { + return e.Str(key, m.Error()) + } case string: return e.Str(key, m) default: @@ -313,7 +381,6 @@ func (e *Event) Errs(key string, errs []error) *Event { // Err adds the field "error" with serialized err to the *Event context. // If err is nil, no field is added. -// To customize the key name, change zerolog.ErrorFieldName. // // To customize the key name, change zerolog.ErrorFieldName. // @@ -330,7 +397,9 @@ func (e *Event) Err(err error) *Event { case LogObjectMarshaler: e.Object(ErrorStackFieldName, m) case error: - e.Str(ErrorStackFieldName, m.Error()) + if m != nil && !isNilValue(m) { + e.Str(ErrorStackFieldName, m.Error()) + } case string: e.Str(ErrorStackFieldName, m) default: @@ -350,6 +419,28 @@ func (e *Event) Stack() *Event { return e } +// Ctx adds the Go Context to the *Event context. The context is not rendered +// in the output message, but is available to hooks and to Func() calls via the +// GetCtx() accessor. A typical use case is to extract tracing information from +// the Go Ctx. +func (e *Event) Ctx(ctx context.Context) *Event { + if e != nil { + e.ctx = ctx + } + return e +} + +// GetCtx retrieves the Go context.Context which is optionally stored in the +// Event. This allows Hooks and functions passed to Func() to retrieve values +// which are stored in the context.Context. This can be useful in tracing, +// where span information is commonly propagated in the context.Context. +func (e *Event) GetCtx() context.Context { + if e == nil || e.ctx == nil { + return context.Background() + } + return e.ctx +} + // Bool adds the field key with val as a bool to the *Event context. func (e *Event) Bool(key string, b bool) *Event { if e == nil { @@ -597,7 +688,7 @@ func (e *Event) Timestamp() *Event { return e } -// Time adds the field key with t formated as string using zerolog.TimeFieldFormat. +// Time adds the field key with t formatted as string using zerolog.TimeFieldFormat. func (e *Event) Time(key string, t time.Time) *Event { if e == nil { return e @@ -606,7 +697,7 @@ func (e *Event) Time(key string, t time.Time) *Event { return e } -// Times adds the field key with t formated as string using zerolog.TimeFieldFormat. +// Times adds the field key with t formatted as string using zerolog.TimeFieldFormat. func (e *Event) Times(key string, t []time.Time) *Event { if e == nil { return e @@ -652,6 +743,11 @@ func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Event { return e } +// Any is a wrapper around Event.Interface. +func (e *Event) Any(key string, i interface{}) *Event { + return e.Interface(key, i) +} + // Interface adds the field key with i marshaled using reflection. func (e *Event) Interface(key string, i interface{}) *Event { if e == nil { @@ -664,6 +760,25 @@ func (e *Event) Interface(key string, i interface{}) *Event { return e } +// Type adds the field key with val's type using reflection. +func (e *Event) Type(key string, val interface{}) *Event { + if e == nil { + return e + } + e.buf = enc.AppendType(enc.AppendKey(e.buf, key), val) + return e +} + +// CallerSkipFrame instructs any future Caller calls to skip the specified number of frames. +// This includes those added via hooks from the context. +func (e *Event) CallerSkipFrame(skip int) *Event { + if e == nil { + return e + } + e.skipFrame += skip + return e +} + // Caller adds the file:line of the caller with the zerolog.CallerFieldName key. // The argument skip is the number of stack frames to ascend // Skip If not passed, use the global variable CallerSkipFrameCount @@ -679,11 +794,11 @@ func (e *Event) caller(skip int) *Event { if e == nil { return e } - _, file, line, ok := runtime.Caller(skip) + pc, file, line, ok := runtime.Caller(skip + e.skipFrame) if !ok { return e } - e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(file, line)) + e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(pc, file, line)) return e } diff --git a/vendor/github.com/rs/zerolog/example.jsonl b/vendor/github.com/rs/zerolog/example.jsonl new file mode 100644 index 000000000..d73193d7d --- /dev/null +++ b/vendor/github.com/rs/zerolog/example.jsonl @@ -0,0 +1,7 @@ +{"time":"5:41PM","level":"info","message":"Starting listener","listen":":8080","pid":37556} +{"time":"5:41PM","level":"debug","message":"Access","database":"myapp","host":"localhost:4962","pid":37556} +{"time":"5:41PM","level":"info","message":"Access","method":"GET","path":"/users","pid":37556,"resp_time":23} +{"time":"5:41PM","level":"info","message":"Access","method":"POST","path":"/posts","pid":37556,"resp_time":532} +{"time":"5:41PM","level":"warn","message":"Slow request","method":"POST","path":"/posts","pid":37556,"resp_time":532} +{"time":"5:41PM","level":"info","message":"Access","method":"GET","path":"/users","pid":37556,"resp_time":10} +{"time":"5:41PM","level":"error","message":"Database connection lost","database":"myapp","pid":37556,"error":"connection reset by peer"} diff --git a/vendor/github.com/rs/zerolog/fields.go b/vendor/github.com/rs/zerolog/fields.go index 6b62ecc28..23606ddd5 100644 --- a/vendor/github.com/rs/zerolog/fields.go +++ b/vendor/github.com/rs/zerolog/fields.go @@ -1,20 +1,47 @@ package zerolog import ( + "encoding/json" "net" "sort" "time" + "unsafe" ) -func appendFields(dst []byte, fields map[string]interface{}) []byte { - keys := make([]string, 0, len(fields)) - for key := range fields { - keys = append(keys, key) +func isNilValue(i interface{}) bool { + return (*[2]uintptr)(unsafe.Pointer(&i))[1] == 0 +} + +func appendFields(dst []byte, fields interface{}, stack bool) []byte { + switch fields := fields.(type) { + case []interface{}: + if n := len(fields); n&0x1 == 1 { // odd number + fields = fields[:n-1] + } + dst = appendFieldList(dst, fields, stack) + case map[string]interface{}: + keys := make([]string, 0, len(fields)) + for key := range fields { + keys = append(keys, key) + } + sort.Strings(keys) + kv := make([]interface{}, 2) + for _, key := range keys { + kv[0], kv[1] = key, fields[key] + dst = appendFieldList(dst, kv, stack) + } } - sort.Strings(keys) - for _, key := range keys { - dst = enc.AppendKey(dst, key) - val := fields[key] + return dst +} + +func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte { + for i, n := 0, len(kvList); i < n; i += 2 { + key, val := kvList[i], kvList[i+1] + if key, ok := key.(string); ok { + dst = enc.AppendKey(dst, key) + } else { + continue + } if val, ok := val.(LogObjectMarshaler); ok { e := newEvent(nil, 0) e.buf = e.buf[:0] @@ -29,8 +56,7 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { case []byte: dst = enc.AppendBytes(dst, val) case error: - marshaled := ErrorMarshalFunc(val) - switch m := marshaled.(type) { + switch m := ErrorMarshalFunc(val).(type) { case LogObjectMarshaler: e := newEvent(nil, 0) e.buf = e.buf[:0] @@ -38,17 +64,35 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { dst = append(dst, e.buf...) putEvent(e) case error: - dst = enc.AppendString(dst, m.Error()) + if m == nil || isNilValue(m) { + dst = enc.AppendNil(dst) + } else { + dst = enc.AppendString(dst, m.Error()) + } case string: dst = enc.AppendString(dst, m) default: dst = enc.AppendInterface(dst, m) } + + if stack && ErrorStackMarshaler != nil { + dst = enc.AppendKey(dst, ErrorStackFieldName) + switch m := ErrorStackMarshaler(val).(type) { + case nil: + case error: + if m != nil && !isNilValue(m) { + dst = enc.AppendString(dst, m.Error()) + } + case string: + dst = enc.AppendString(dst, m) + default: + dst = enc.AppendInterface(dst, m) + } + } case []error: dst = enc.AppendArrayStart(dst) for i, err := range val { - marshaled := ErrorMarshalFunc(err) - switch m := marshaled.(type) { + switch m := ErrorMarshalFunc(err).(type) { case LogObjectMarshaler: e := newEvent(nil, 0) e.buf = e.buf[:0] @@ -56,7 +100,11 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { dst = append(dst, e.buf...) putEvent(e) case error: - dst = enc.AppendString(dst, m.Error()) + if m == nil || isNilValue(m) { + dst = enc.AppendNil(dst) + } else { + dst = enc.AppendString(dst, m.Error()) + } case string: dst = enc.AppendString(dst, m) default: @@ -234,6 +282,8 @@ func appendFields(dst []byte, fields map[string]interface{}) []byte { dst = enc.AppendIPPrefix(dst, val) case net.HardwareAddr: dst = enc.AppendMACAddr(dst, val) + case json.RawMessage: + dst = appendJSON(dst, val) default: dst = enc.AppendInterface(dst, val) } diff --git a/vendor/github.com/rs/zerolog/globals.go b/vendor/github.com/rs/zerolog/globals.go index 421429a52..b38a7fcee 100644 --- a/vendor/github.com/rs/zerolog/globals.go +++ b/vendor/github.com/rs/zerolog/globals.go @@ -1,6 +1,7 @@ package zerolog import ( + "encoding/json" "strconv" "sync/atomic" "time" @@ -18,6 +19,10 @@ const ( // TimeFormatUnixMicro defines a time format that makes time fields to be // serialized as Unix timestamp integers in microseconds. TimeFormatUnixMicro = "UNIXMICRO" + + // TimeFormatUnixNano defines a time format that makes time fields to be + // serialized as Unix timestamp integers in nanoseconds. + TimeFormatUnixNano = "UNIXNANO" ) var ( @@ -27,7 +32,22 @@ var ( // LevelFieldName is the field name used for the level field. LevelFieldName = "level" - // LevelFieldMarshalFunc allows customization of global level field marshaling + // LevelTraceValue is the value used for the trace level field. + LevelTraceValue = "trace" + // LevelDebugValue is the value used for the debug level field. + LevelDebugValue = "debug" + // LevelInfoValue is the value used for the info level field. + LevelInfoValue = "info" + // LevelWarnValue is the value used for the warn level field. + LevelWarnValue = "warn" + // LevelErrorValue is the value used for the error level field. + LevelErrorValue = "error" + // LevelFatalValue is the value used for the fatal level field. + LevelFatalValue = "fatal" + // LevelPanicValue is the value used for the panic level field. + LevelPanicValue = "panic" + + // LevelFieldMarshalFunc allows customization of global level field marshaling. LevelFieldMarshalFunc = func(l Level) string { return l.String() } @@ -45,7 +65,7 @@ var ( CallerSkipFrameCount = 2 // CallerMarshalFunc allows customization of global caller marshaling - CallerMarshalFunc = func(file string, line int) string { + CallerMarshalFunc = func(pc uintptr, file string, line int) string { return file + ":" + strconv.Itoa(line) } @@ -60,8 +80,12 @@ var ( return err } + // InterfaceMarshalFunc allows customization of interface marshaling. + // Default: "encoding/json.Marshal" + InterfaceMarshalFunc = json.Marshal + // TimeFieldFormat defines the time format of the Time field type. If set to - // TimeFormatUnix, TimeFormatUnixMs or TimeFormatUnixMicro, the time is formatted as an UNIX + // TimeFormatUnix, TimeFormatUnixMs, TimeFormatUnixMicro or TimeFormatUnixNano, the time is formatted as a UNIX // timestamp as integer. TimeFieldFormat = time.RFC3339 @@ -80,6 +104,38 @@ var ( // output. If not set, an error is printed on the stderr. This handler must // be thread safe and non-blocking. ErrorHandler func(err error) + + // DefaultContextLogger is returned from Ctx() if there is no logger associated + // with the context. + DefaultContextLogger *Logger + + // LevelColors are used by ConsoleWriter's consoleDefaultFormatLevel to color + // log levels. + LevelColors = map[Level]int{ + TraceLevel: colorBlue, + DebugLevel: 0, + InfoLevel: colorGreen, + WarnLevel: colorYellow, + ErrorLevel: colorRed, + FatalLevel: colorRed, + PanicLevel: colorRed, + } + + // FormattedLevels are used by ConsoleWriter's consoleDefaultFormatLevel + // for a short level name. + FormattedLevels = map[Level]string{ + TraceLevel: "TRC", + DebugLevel: "DBG", + InfoLevel: "INF", + WarnLevel: "WRN", + ErrorLevel: "ERR", + FatalLevel: "FTL", + PanicLevel: "PNC", + } + + // TriggerLevelWriterBufferReuseLimit is a limit in bytes that a buffer is dropped + // from the TriggerLevelWriter buffer pool if the buffer grows above the limit. + TriggerLevelWriterBufferReuseLimit = 64 * 1024 ) var ( diff --git a/vendor/github.com/rs/zerolog/internal/cbor/base.go b/vendor/github.com/rs/zerolog/internal/cbor/base.go index 58cd0822b..51fe86c9b 100644 --- a/vendor/github.com/rs/zerolog/internal/cbor/base.go +++ b/vendor/github.com/rs/zerolog/internal/cbor/base.go @@ -1,5 +1,13 @@ package cbor +// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice. +// Making it package level instead of embedded in Encoder brings +// some extra efforts at importing, but avoids value copy when the functions +// of Encoder being invoked. +// DO REMEMBER to set this variable at importing, or +// you might get a nil pointer dereference panic at runtime. +var JSONMarshalFunc func(v interface{}) ([]byte, error) + type Encoder struct{} // AppendKey adds a key (string) to the binary encoded log message @@ -8,4 +16,4 @@ func (e Encoder) AppendKey(dst []byte, key string) []byte { dst = e.AppendBeginMarker(dst) } return e.AppendString(dst, key) -} \ No newline at end of file +} diff --git a/vendor/github.com/rs/zerolog/internal/cbor/cbor.go b/vendor/github.com/rs/zerolog/internal/cbor/cbor.go index 969f59159..1bf144380 100644 --- a/vendor/github.com/rs/zerolog/internal/cbor/cbor.go +++ b/vendor/github.com/rs/zerolog/internal/cbor/cbor.go @@ -26,7 +26,8 @@ const ( additionalTypeBreak byte = 31 // Tag Sub-types. - additionalTypeTimestamp byte = 01 + additionalTypeTimestamp byte = 01 + additionalTypeEmbeddedCBOR byte = 63 // Extended Tags - from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml additionalTypeTagNetworkAddr uint16 = 260 @@ -67,7 +68,7 @@ const ( var IntegerTimeFieldFormat = time.RFC3339 // NanoTimeFieldFormat indicates the format of timestamp decoded -// from a float value (time in seconds and nano seconds). +// from a float value (time in seconds and nanoseconds). var NanoTimeFieldFormat = time.RFC3339Nano func appendCborTypePrefix(dst []byte, major byte, number uint64) []byte { @@ -91,7 +92,8 @@ func appendCborTypePrefix(dst []byte, major byte, number uint64) []byte { minor = additionalTypeIntUint64 } - dst = append(dst, byte(major|minor)) + + dst = append(dst, major|minor) byteCount-- for ; byteCount >= 0; byteCount-- { dst = append(dst, byte(number>>(uint(byteCount)*8))) diff --git a/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go b/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go index e3cf3b7db..616bed65d 100644 --- a/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go +++ b/vendor/github.com/rs/zerolog/internal/cbor/decode_stream.go @@ -5,6 +5,7 @@ package cbor import ( "bufio" "bytes" + "encoding/base64" "fmt" "io" "math" @@ -43,7 +44,7 @@ func readByte(src *bufio.Reader) byte { return b } -func decodeIntAdditonalType(src *bufio.Reader, minor byte) int64 { +func decodeIntAdditionalType(src *bufio.Reader, minor byte) int64 { val := int64(0) if minor <= 23 { val = int64(minor) @@ -77,7 +78,7 @@ func decodeInteger(src *bufio.Reader) int64 { if major != majorTypeUnsignedInt && major != majorTypeNegativeInt { panic(fmt.Errorf("Major type is: %d in decodeInteger!! (expected 0 or 1)", major)) } - val := decodeIntAdditonalType(src, minor) + val := decodeIntAdditionalType(src, minor) if major == 0 { return val } @@ -204,7 +205,7 @@ func decodeString(src *bufio.Reader, noQuotes bool) []byte { if !noQuotes { result = append(result, '"') } - length := decodeIntAdditonalType(src, minor) + length := decodeIntAdditionalType(src, minor) len := int(length) pbs := readNBytes(src, len) result = append(result, pbs...) @@ -213,6 +214,31 @@ func decodeString(src *bufio.Reader, noQuotes bool) []byte { } return append(result, '"') } +func decodeStringToDataUrl(src *bufio.Reader, mimeType string) []byte { + pb := readByte(src) + major := pb & maskOutAdditionalType + minor := pb & maskOutMajorType + if major != majorTypeByteString { + panic(fmt.Errorf("Major type is: %d in decodeString", major)) + } + length := decodeIntAdditionalType(src, minor) + l := int(length) + enc := base64.StdEncoding + lEnc := enc.EncodedLen(l) + result := make([]byte, len("\"data:;base64,\"")+len(mimeType)+lEnc) + dest := result + u := copy(dest, "\"data:") + dest = dest[u:] + u = copy(dest, mimeType) + dest = dest[u:] + u = copy(dest, ";base64,") + dest = dest[u:] + pbs := readNBytes(src, l) + enc.Encode(dest, pbs) + dest = dest[lEnc:] + dest[0] = '"' + return result +} func decodeUTF8String(src *bufio.Reader) []byte { pb := readByte(src) @@ -222,7 +248,7 @@ func decodeUTF8String(src *bufio.Reader) []byte { panic(fmt.Errorf("Major type is: %d in decodeUTF8String", major)) } result := []byte{'"'} - length := decodeIntAdditonalType(src, minor) + length := decodeIntAdditionalType(src, minor) len := int(length) pbs := readNBytes(src, len) @@ -238,7 +264,7 @@ func decodeUTF8String(src *bufio.Reader) []byte { return append(dst, '"') } } - // The string has no need for encoding an therefore is directly + // The string has no need for encoding and therefore is directly // appended to the byte slice. result = append(result, pbs...) return append(result, '"') @@ -257,7 +283,7 @@ func array2Json(src *bufio.Reader, dst io.Writer) { if minor == additionalTypeInfiniteCount { unSpecifiedCount = true } else { - length := decodeIntAdditonalType(src, minor) + length := decodeIntAdditionalType(src, minor) len = int(length) } for i := 0; unSpecifiedCount || i < len; i++ { @@ -266,7 +292,7 @@ func array2Json(src *bufio.Reader, dst io.Writer) { if e != nil { panic(e) } - if pb[0] == byte(majorTypeSimpleAndFloat|additionalTypeBreak) { + if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak { readByte(src) break } @@ -277,7 +303,7 @@ func array2Json(src *bufio.Reader, dst io.Writer) { if e != nil { panic(e) } - if pb[0] == byte(majorTypeSimpleAndFloat|additionalTypeBreak) { + if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak { readByte(src) break } @@ -301,7 +327,7 @@ func map2Json(src *bufio.Reader, dst io.Writer) { if minor == additionalTypeInfiniteCount { unSpecifiedCount = true } else { - length := decodeIntAdditonalType(src, minor) + length := decodeIntAdditionalType(src, minor) len = int(length) } dst.Write([]byte{'{'}) @@ -311,7 +337,7 @@ func map2Json(src *bufio.Reader, dst io.Writer) { if e != nil { panic(e) } - if pb[0] == byte(majorTypeSimpleAndFloat|additionalTypeBreak) { + if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak { readByte(src) break } @@ -326,7 +352,7 @@ func map2Json(src *bufio.Reader, dst io.Writer) { if e != nil { panic(e) } - if pb[0] == byte(majorTypeSimpleAndFloat|additionalTypeBreak) { + if pb[0] == majorTypeSimpleAndFloat|additionalTypeBreak { readByte(src) break } @@ -349,10 +375,24 @@ func decodeTagData(src *bufio.Reader) []byte { switch minor { case additionalTypeTimestamp: return decodeTimeStamp(src) + case additionalTypeIntUint8: + val := decodeIntAdditionalType(src, minor) + switch byte(val) { + case additionalTypeEmbeddedCBOR: + pb := readByte(src) + dataMajor := pb & maskOutAdditionalType + if dataMajor != majorTypeByteString { + panic(fmt.Errorf("Unsupported embedded Type: %d in decodeEmbeddedCBOR", dataMajor)) + } + src.UnreadByte() + return decodeStringToDataUrl(src, "application/cbor") + default: + panic(fmt.Errorf("Unsupported Additional Tag Type: %d in decodeTagData", val)) + } // Tag value is larger than 256 (so uint16). case additionalTypeIntUint16: - val := decodeIntAdditonalType(src, minor) + val := decodeIntAdditionalType(src, minor) switch uint16(val) { case additionalTypeEmbeddedJSON: @@ -383,7 +423,7 @@ func decodeTagData(src *bufio.Reader) []byte { case additionalTypeTagNetworkPrefix: pb := readByte(src) - if pb != byte(majorTypeMap|0x1) { + if pb != majorTypeMap|0x1 { panic(fmt.Errorf("IP Prefix is NOT of MAP of 1 elements as expected")) } octets := decodeString(src, true) diff --git a/vendor/github.com/rs/zerolog/internal/cbor/string.go b/vendor/github.com/rs/zerolog/internal/cbor/string.go index ff42afab4..9fc9a4f8e 100644 --- a/vendor/github.com/rs/zerolog/internal/cbor/string.go +++ b/vendor/github.com/rs/zerolog/internal/cbor/string.go @@ -1,12 +1,14 @@ package cbor +import "fmt" + // AppendStrings encodes and adds an array of strings to the dst byte array. func (e Encoder) AppendStrings(dst []byte, vals []string) []byte { major := majorTypeArray l := len(vals) if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -23,13 +25,38 @@ func (Encoder) AppendString(dst []byte, s string) []byte { l := len(s) if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, majorTypeUtf8String, uint64(l)) } return append(dst, s...) } +// AppendStringers encodes and adds an array of Stringer values +// to the dst byte array. +func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte { + if len(vals) == 0 { + return e.AppendArrayEnd(e.AppendArrayStart(dst)) + } + dst = e.AppendArrayStart(dst) + dst = e.AppendStringer(dst, vals[0]) + if len(vals) > 1 { + for _, val := range vals[1:] { + dst = e.AppendStringer(dst, val) + } + } + return e.AppendArrayEnd(dst) +} + +// AppendStringer encodes and adds the Stringer value to the dst +// byte array. +func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte { + if val == nil { + return e.AppendNil(dst) + } + return e.AppendString(dst, val.String()) +} + // AppendBytes encodes and adds an array of bytes to the dst byte array. func (Encoder) AppendBytes(dst, s []byte) []byte { major := majorTypeByteString @@ -37,7 +64,7 @@ func (Encoder) AppendBytes(dst, s []byte) []byte { l := len(s) if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -50,7 +77,7 @@ func AppendEmbeddedJSON(dst, s []byte) []byte { minor := additionalTypeEmbeddedJSON // Append the TAG to indicate this is Embedded JSON. - dst = append(dst, byte(major|additionalTypeIntUint16)) + dst = append(dst, major|additionalTypeIntUint16) dst = append(dst, byte(minor>>8)) dst = append(dst, byte(minor&0xff)) @@ -60,7 +87,29 @@ func AppendEmbeddedJSON(dst, s []byte) []byte { l := len(s) if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) + } else { + dst = appendCborTypePrefix(dst, major, uint64(l)) + } + return append(dst, s...) +} + +// AppendEmbeddedCBOR adds a tag and embeds input CBOR as such. +func AppendEmbeddedCBOR(dst, s []byte) []byte { + major := majorTypeTags + minor := additionalTypeEmbeddedCBOR + + // Append the TAG to indicate this is Embedded JSON. + dst = append(dst, major|additionalTypeIntUint8) + dst = append(dst, minor) + + // Append the CBOR Object as Byte String. + major = majorTypeByteString + + l := len(s) + if l <= additionalMax { + lb := byte(l) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } diff --git a/vendor/github.com/rs/zerolog/internal/cbor/time.go b/vendor/github.com/rs/zerolog/internal/cbor/time.go index 12f6a1ddd..d81fb1257 100644 --- a/vendor/github.com/rs/zerolog/internal/cbor/time.go +++ b/vendor/github.com/rs/zerolog/internal/cbor/time.go @@ -7,7 +7,7 @@ import ( func appendIntegerTimestamp(dst []byte, t time.Time) []byte { major := majorTypeTags minor := additionalTypeTimestamp - dst = append(dst, byte(major|minor)) + dst = append(dst, major|minor) secs := t.Unix() var val uint64 if secs < 0 { @@ -17,18 +17,18 @@ func appendIntegerTimestamp(dst []byte, t time.Time) []byte { major = majorTypeUnsignedInt val = uint64(secs) } - dst = appendCborTypePrefix(dst, major, uint64(val)) + dst = appendCborTypePrefix(dst, major, val) return dst } func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte { major := majorTypeTags minor := additionalTypeTimestamp - dst = append(dst, byte(major|minor)) + dst = append(dst, major|minor) secs := t.Unix() nanos := t.Nanosecond() var val float64 - val = float64(secs)*1.0 + float64(nanos)*1E-9 + val = float64(secs)*1.0 + float64(nanos)*1e-9 return e.AppendFloat64(dst, val) } @@ -50,7 +50,7 @@ func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string) []byte } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -82,7 +82,7 @@ func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Dur } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } diff --git a/vendor/github.com/rs/zerolog/internal/cbor/types.go b/vendor/github.com/rs/zerolog/internal/cbor/types.go index 3d76ea08e..6f5383289 100644 --- a/vendor/github.com/rs/zerolog/internal/cbor/types.go +++ b/vendor/github.com/rs/zerolog/internal/cbor/types.go @@ -1,25 +1,25 @@ package cbor import ( - "encoding/json" "fmt" "math" "net" + "reflect" ) // AppendNil inserts a 'Nil' object into the dst byte array. func (Encoder) AppendNil(dst []byte) []byte { - return append(dst, byte(majorTypeSimpleAndFloat|additionalTypeNull)) + return append(dst, majorTypeSimpleAndFloat|additionalTypeNull) } // AppendBeginMarker inserts a map start into the dst byte array. func (Encoder) AppendBeginMarker(dst []byte) []byte { - return append(dst, byte(majorTypeMap|additionalTypeInfiniteCount)) + return append(dst, majorTypeMap|additionalTypeInfiniteCount) } // AppendEndMarker inserts a map end into the dst byte array. func (Encoder) AppendEndMarker(dst []byte) []byte { - return append(dst, byte(majorTypeSimpleAndFloat|additionalTypeBreak)) + return append(dst, majorTypeSimpleAndFloat|additionalTypeBreak) } // AppendObjectData takes an object in form of a byte array and appends to dst. @@ -31,12 +31,12 @@ func (Encoder) AppendObjectData(dst []byte, o []byte) []byte { // AppendArrayStart adds markers to indicate the start of an array. func (Encoder) AppendArrayStart(dst []byte) []byte { - return append(dst, byte(majorTypeArray|additionalTypeInfiniteCount)) + return append(dst, majorTypeArray|additionalTypeInfiniteCount) } // AppendArrayEnd adds markers to indicate the end of an array. func (Encoder) AppendArrayEnd(dst []byte) []byte { - return append(dst, byte(majorTypeSimpleAndFloat|additionalTypeBreak)) + return append(dst, majorTypeSimpleAndFloat|additionalTypeBreak) } // AppendArrayDelim adds markers to indicate end of a particular array element. @@ -57,7 +57,7 @@ func (Encoder) AppendBool(dst []byte, val bool) []byte { if val { b = additionalTypeBoolTrue } - return append(dst, byte(majorTypeSimpleAndFloat|b)) + return append(dst, majorTypeSimpleAndFloat|b) } // AppendBools encodes and inserts an array of boolean values into the dst byte array. @@ -69,7 +69,7 @@ func (e Encoder) AppendBools(dst []byte, vals []bool) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -89,7 +89,7 @@ func (Encoder) AppendInt(dst []byte, val int) []byte { } if contentVal <= additionalMax { lb := byte(contentVal) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(contentVal)) } @@ -105,7 +105,7 @@ func (e Encoder) AppendInts(dst []byte, vals []int) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -129,7 +129,7 @@ func (e Encoder) AppendInts8(dst []byte, vals []int8) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -153,7 +153,7 @@ func (e Encoder) AppendInts16(dst []byte, vals []int16) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -177,7 +177,7 @@ func (e Encoder) AppendInts32(dst []byte, vals []int32) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -197,7 +197,7 @@ func (Encoder) AppendInt64(dst []byte, val int64) []byte { } if contentVal <= additionalMax { lb := byte(contentVal) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(contentVal)) } @@ -213,7 +213,7 @@ func (e Encoder) AppendInts64(dst []byte, vals []int64) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -237,7 +237,7 @@ func (e Encoder) AppendUints(dst []byte, vals []uint) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -261,7 +261,7 @@ func (e Encoder) AppendUints8(dst []byte, vals []uint8) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -285,7 +285,7 @@ func (e Encoder) AppendUints16(dst []byte, vals []uint16) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -309,7 +309,7 @@ func (e Encoder) AppendUints32(dst []byte, vals []uint32) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -325,9 +325,9 @@ func (Encoder) AppendUint64(dst []byte, val uint64) []byte { contentVal := val if contentVal <= additionalMax { lb := byte(contentVal) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { - dst = appendCborTypePrefix(dst, major, uint64(contentVal)) + dst = appendCborTypePrefix(dst, major, contentVal) } return dst } @@ -341,7 +341,7 @@ func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -368,7 +368,7 @@ func (Encoder) AppendFloat32(dst []byte, val float32) []byte { for i := uint(0); i < 4; i++ { buf[i] = byte(n >> ((3 - i) * 8)) } - return append(append(dst, byte(major|subType)), buf[0], buf[1], buf[2], buf[3]) + return append(append(dst, major|subType), buf[0], buf[1], buf[2], buf[3]) } // AppendFloats32 encodes and inserts an array of single precision float value into the dst byte array. @@ -380,7 +380,7 @@ func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -403,7 +403,7 @@ func (Encoder) AppendFloat64(dst []byte, val float64) []byte { major := majorTypeSimpleAndFloat subType := additionalTypeFloat64 n := math.Float64bits(val) - dst = append(dst, byte(major|subType)) + dst = append(dst, major|subType) for i := uint(1); i <= 8; i++ { b := byte(n >> ((8 - i) * 8)) dst = append(dst, b) @@ -420,7 +420,7 @@ func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte { } if l <= additionalMax { lb := byte(l) - dst = append(dst, byte(major|lb)) + dst = append(dst, major|lb) } else { dst = appendCborTypePrefix(dst, major, uint64(l)) } @@ -432,16 +432,24 @@ func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte { // AppendInterface takes an arbitrary object and converts it to JSON and embeds it dst. func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte { - marshaled, err := json.Marshal(i) + marshaled, err := JSONMarshalFunc(i) if err != nil { return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err)) } return AppendEmbeddedJSON(dst, marshaled) } +// AppendType appends the parameter type (as a string) to the input byte slice. +func (e Encoder) AppendType(dst []byte, i interface{}) []byte { + if i == nil { + return e.AppendString(dst, "") + } + return e.AppendString(dst, reflect.TypeOf(i).String()) +} + // AppendIPAddr encodes and inserts an IP Address (IPv4 or IPv6). func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte { - dst = append(dst, byte(majorTypeTags|additionalTypeIntUint16)) + dst = append(dst, majorTypeTags|additionalTypeIntUint16) dst = append(dst, byte(additionalTypeTagNetworkAddr>>8)) dst = append(dst, byte(additionalTypeTagNetworkAddr&0xff)) return e.AppendBytes(dst, ip) @@ -449,21 +457,21 @@ func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte { // AppendIPPrefix encodes and inserts an IP Address Prefix (Address + Mask Length). func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte { - dst = append(dst, byte(majorTypeTags|additionalTypeIntUint16)) + dst = append(dst, majorTypeTags|additionalTypeIntUint16) dst = append(dst, byte(additionalTypeTagNetworkPrefix>>8)) dst = append(dst, byte(additionalTypeTagNetworkPrefix&0xff)) // Prefix is a tuple (aka MAP of 1 pair of elements) - // first element is prefix, second is mask length. - dst = append(dst, byte(majorTypeMap|0x1)) + dst = append(dst, majorTypeMap|0x1) dst = e.AppendBytes(dst, pfx.IP) maskLen, _ := pfx.Mask.Size() return e.AppendUint8(dst, uint8(maskLen)) } -// AppendMACAddr encodes and inserts an Hardware (MAC) address. +// AppendMACAddr encodes and inserts a Hardware (MAC) address. func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte { - dst = append(dst, byte(majorTypeTags|additionalTypeIntUint16)) + dst = append(dst, majorTypeTags|additionalTypeIntUint16) dst = append(dst, byte(additionalTypeTagNetworkAddr>>8)) dst = append(dst, byte(additionalTypeTagNetworkAddr&0xff)) return e.AppendBytes(dst, ha) @@ -471,7 +479,7 @@ func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte { // AppendHex adds a TAG and inserts a hex bytes as a string. func (e Encoder) AppendHex(dst []byte, val []byte) []byte { - dst = append(dst, byte(majorTypeTags|additionalTypeIntUint16)) + dst = append(dst, majorTypeTags|additionalTypeIntUint16) dst = append(dst, byte(additionalTypeTagHexString>>8)) dst = append(dst, byte(additionalTypeTagHexString&0xff)) return e.AppendBytes(dst, val) diff --git a/vendor/github.com/rs/zerolog/internal/json/base.go b/vendor/github.com/rs/zerolog/internal/json/base.go index d6f8839e3..09ec59f4e 100644 --- a/vendor/github.com/rs/zerolog/internal/json/base.go +++ b/vendor/github.com/rs/zerolog/internal/json/base.go @@ -1,12 +1,19 @@ package json +// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice. +// Making it package level instead of embedded in Encoder brings +// some extra efforts at importing, but avoids value copy when the functions +// of Encoder being invoked. +// DO REMEMBER to set this variable at importing, or +// you might get a nil pointer dereference panic at runtime. +var JSONMarshalFunc func(v interface{}) ([]byte, error) + type Encoder struct{} // AppendKey appends a new key to the output JSON. func (e Encoder) AppendKey(dst []byte, key string) []byte { - if len(dst) > 1 && dst[len(dst)-1] != '{' { + if dst[len(dst)-1] != '{' { dst = append(dst, ',') } - dst = e.AppendString(dst, key) - return append(dst, ':') -} \ No newline at end of file + return append(e.AppendString(dst, key), ':') +} diff --git a/vendor/github.com/rs/zerolog/internal/json/string.go b/vendor/github.com/rs/zerolog/internal/json/string.go index 815906ff7..fd7770f2f 100644 --- a/vendor/github.com/rs/zerolog/internal/json/string.go +++ b/vendor/github.com/rs/zerolog/internal/json/string.go @@ -1,6 +1,9 @@ package json -import "unicode/utf8" +import ( + "fmt" + "unicode/utf8" +) const hex = "0123456789abcdef" @@ -34,7 +37,7 @@ func (e Encoder) AppendStrings(dst []byte, vals []string) []byte { // // The operation loops though each byte in the string looking // for characters that need json or utf8 encoding. If the string -// does not need encoding, then the string is appended in it's +// does not need encoding, then the string is appended in its // entirety to the byte slice. // If we encounter a byte that does need encoding, switch up // the operation and perform a byte-by-byte read-encode-append. @@ -53,14 +56,39 @@ func (Encoder) AppendString(dst []byte, s string) []byte { return append(dst, '"') } } - // The string has no need for encoding an therefore is directly + // The string has no need for encoding and therefore is directly // appended to the byte slice. dst = append(dst, s...) // End with a double quote return append(dst, '"') } -// appendStringComplex is used by appendString to take over an in +// AppendStringers encodes the provided Stringer list to json and +// appends the encoded Stringer list to the input byte slice. +func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte { + if len(vals) == 0 { + return append(dst, '[', ']') + } + dst = append(dst, '[') + dst = e.AppendStringer(dst, vals[0]) + if len(vals) > 1 { + for _, val := range vals[1:] { + dst = e.AppendStringer(append(dst, ','), val) + } + } + return append(dst, ']') +} + +// AppendStringer encodes the input Stringer to json and appends the +// encoded Stringer value to the input byte slice. +func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte { + if val == nil { + return e.AppendInterface(dst, nil) + } + return e.AppendString(dst, val.String()) +} + +//// appendStringComplex is used by appendString to take over an in // progress JSON string encoding that encountered a character that needs // to be encoded. func appendStringComplex(dst []byte, s string, i int) []byte { @@ -71,7 +99,7 @@ func appendStringComplex(dst []byte, s string, i int) []byte { r, size := utf8.DecodeRuneInString(s[i:]) if r == utf8.RuneError && size == 1 { // In case of error, first append previous simple characters to - // the byte slice if any and append a remplacement character code + // the byte slice if any and append a replacement character code // in place of the invalid sequence. if start < i { dst = append(dst, s[start:i]...) diff --git a/vendor/github.com/rs/zerolog/internal/json/time.go b/vendor/github.com/rs/zerolog/internal/json/time.go index 5aff6be33..6a8dc912d 100644 --- a/vendor/github.com/rs/zerolog/internal/json/time.go +++ b/vendor/github.com/rs/zerolog/internal/json/time.go @@ -7,9 +7,10 @@ import ( const ( // Import from zerolog/global.go - timeFormatUnix = "" - timeFormatUnixMs = "UNIXMS" + timeFormatUnix = "" + timeFormatUnixMs = "UNIXMS" timeFormatUnixMicro = "UNIXMICRO" + timeFormatUnixNano = "UNIXNANO" ) // AppendTime formats the input time with the given format @@ -22,6 +23,8 @@ func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte { return e.AppendInt64(dst, t.UnixNano()/1000000) case timeFormatUnixMicro: return e.AppendInt64(dst, t.UnixNano()/1000) + case timeFormatUnixNano: + return e.AppendInt64(dst, t.UnixNano()) } return append(t.AppendFormat(append(dst, '"'), format), '"') } @@ -33,7 +36,11 @@ func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) []byte { case timeFormatUnix: return appendUnixTimes(dst, vals) case timeFormatUnixMs: - return appendUnixMsTimes(dst, vals) + return appendUnixNanoTimes(dst, vals, 1000000) + case timeFormatUnixMicro: + return appendUnixNanoTimes(dst, vals, 1000) + case timeFormatUnixNano: + return appendUnixNanoTimes(dst, vals, 1) } if len(vals) == 0 { return append(dst, '[', ']') @@ -64,15 +71,15 @@ func appendUnixTimes(dst []byte, vals []time.Time) []byte { return dst } -func appendUnixMsTimes(dst []byte, vals []time.Time) []byte { +func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte { if len(vals) == 0 { return append(dst, '[', ']') } dst = append(dst, '[') - dst = strconv.AppendInt(dst, vals[0].UnixNano()/1000000, 10) + dst = strconv.AppendInt(dst, vals[0].UnixNano()/div, 10) if len(vals) > 1 { for _, t := range vals[1:] { - dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/1000000, 10) + dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/div, 10) } } dst = append(dst, ']') diff --git a/vendor/github.com/rs/zerolog/internal/json/types.go b/vendor/github.com/rs/zerolog/internal/json/types.go index bc8bc0957..ef3a2a7a3 100644 --- a/vendor/github.com/rs/zerolog/internal/json/types.go +++ b/vendor/github.com/rs/zerolog/internal/json/types.go @@ -1,10 +1,10 @@ package json import ( - "encoding/json" "fmt" "math" "net" + "reflect" "strconv" ) @@ -279,7 +279,7 @@ func (Encoder) AppendUints32(dst []byte, vals []uint32) []byte { // AppendUint64 converts the input uint64 to a string and // appends the encoded string to the input byte slice. func (Encoder) AppendUint64(dst []byte, val uint64) []byte { - return strconv.AppendUint(dst, uint64(val), 10) + return strconv.AppendUint(dst, val, 10) } // AppendUints64 encodes the input uint64s to json and @@ -301,7 +301,7 @@ func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte { func appendFloat(dst []byte, val float64, bitSize int) []byte { // JSON does not permit NaN or Infinity. A typical JSON encoder would fail - // with an error, but a logging library wants the data to get thru so we + // with an error, but a logging library wants the data to get through so we // make a tradeoff and store those types as string. switch { case math.IsNaN(val): @@ -350,7 +350,7 @@ func (Encoder) AppendFloats64(dst []byte, vals []float64) []byte { return append(dst, '[', ']') } dst = append(dst, '[') - dst = appendFloat(dst, vals[0], 32) + dst = appendFloat(dst, vals[0], 64) if len(vals) > 1 { for _, val := range vals[1:] { dst = appendFloat(append(dst, ','), val, 64) @@ -363,13 +363,21 @@ func (Encoder) AppendFloats64(dst []byte, vals []float64) []byte { // AppendInterface marshals the input interface to a string and // appends the encoded string to the input byte slice. func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte { - marshaled, err := json.Marshal(i) + marshaled, err := JSONMarshalFunc(i) if err != nil { return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err)) } return append(dst, marshaled...) } +// AppendType appends the parameter type (as a string) to the input byte slice. +func (e Encoder) AppendType(dst []byte, i interface{}) []byte { + if i == nil { + return e.AppendString(dst, "") + } + return e.AppendString(dst, reflect.TypeOf(i).String()) +} + // AppendObjectData takes in an object that is already in a byte array // and adds it to the dst. func (Encoder) AppendObjectData(dst []byte, o []byte) []byte { @@ -379,11 +387,10 @@ func (Encoder) AppendObjectData(dst []byte, o []byte) []byte { // to separate with existing content OR // 3. existing content has already other fields if o[0] == '{' { - if len(dst) == 0 { - o = o[1:] - } else { - o[0] = ',' + if len(dst) > 1 { + dst = append(dst, ',') } + o = o[1:] } else if len(dst) > 1 { dst = append(dst, ',') } diff --git a/vendor/github.com/rs/zerolog/log.go b/vendor/github.com/rs/zerolog/log.go index 0af296c9a..9fec7cc31 100644 --- a/vendor/github.com/rs/zerolog/log.go +++ b/vendor/github.com/rs/zerolog/log.go @@ -82,8 +82,9 @@ // log.Warn().Msg("") // // Output: {"level":"warn","severity":"warn"} // +// # Caveats // -// Caveats +// Field duplication: // // There is no fields deduplication out-of-the-box. // Using the same key multiple times creates new key in final JSON each time. @@ -96,14 +97,30 @@ // // In this case, many consumers will take the last value, // but this is not guaranteed; check yours if in doubt. +// +// Concurrency safety: +// +// Be careful when calling UpdateContext. It is not concurrency safe. Use the With method to create a child logger: +// +// func handler(w http.ResponseWriter, r *http.Request) { +// // Create a child logger for concurrency safety +// logger := log.Logger.With().Logger() +// +// // Add context fields, for example User-Agent from HTTP headers +// logger.UpdateContext(func(c zerolog.Context) zerolog.Context { +// ... +// }) +// } package zerolog import ( + "context" + "errors" "fmt" "io" - "io/ioutil" "os" "strconv" + "strings" ) // Level defines log levels. @@ -129,57 +146,84 @@ const ( // TraceLevel defines trace log level. TraceLevel Level = -1 + // Values less than TraceLevel are handled as numbers. ) func (l Level) String() string { switch l { case TraceLevel: - return "trace" + return LevelTraceValue case DebugLevel: - return "debug" + return LevelDebugValue case InfoLevel: - return "info" + return LevelInfoValue case WarnLevel: - return "warn" + return LevelWarnValue case ErrorLevel: - return "error" + return LevelErrorValue case FatalLevel: - return "fatal" + return LevelFatalValue case PanicLevel: - return "panic" + return LevelPanicValue + case Disabled: + return "disabled" case NoLevel: return "" } - return "" + return strconv.Itoa(int(l)) } // ParseLevel converts a level string into a zerolog Level value. // returns an error if the input string does not match known values. func ParseLevel(levelStr string) (Level, error) { - switch levelStr { - case LevelFieldMarshalFunc(TraceLevel): + switch { + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(TraceLevel)): return TraceLevel, nil - case LevelFieldMarshalFunc(DebugLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(DebugLevel)): return DebugLevel, nil - case LevelFieldMarshalFunc(InfoLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(InfoLevel)): return InfoLevel, nil - case LevelFieldMarshalFunc(WarnLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(WarnLevel)): return WarnLevel, nil - case LevelFieldMarshalFunc(ErrorLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(ErrorLevel)): return ErrorLevel, nil - case LevelFieldMarshalFunc(FatalLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(FatalLevel)): return FatalLevel, nil - case LevelFieldMarshalFunc(PanicLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(PanicLevel)): return PanicLevel, nil - case LevelFieldMarshalFunc(NoLevel): + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(Disabled)): + return Disabled, nil + case strings.EqualFold(levelStr, LevelFieldMarshalFunc(NoLevel)): return NoLevel, nil } - return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr) + i, err := strconv.Atoi(levelStr) + if err != nil { + return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr) + } + if i > 127 || i < -128 { + return NoLevel, fmt.Errorf("Out-Of-Bounds Level: '%d', defaulting to NoLevel", i) + } + return Level(i), nil +} + +// UnmarshalText implements encoding.TextUnmarshaler to allow for easy reading from toml/yaml/json formats +func (l *Level) UnmarshalText(text []byte) error { + if l == nil { + return errors.New("can't unmarshal a nil *Level") + } + var err error + *l, err = ParseLevel(string(text)) + return err +} + +// MarshalText implements encoding.TextMarshaler to allow for easy writing into toml/yaml/json formats +func (l Level) MarshalText() ([]byte, error) { + return []byte(LevelFieldMarshalFunc(l)), nil } // A Logger represents an active logging object that generates lines // of JSON output to an io.Writer. Each logging operation makes a single -// call to the Writer's Write method. There is no guaranty on access +// call to the Writer's Write method. There is no guarantee on access // serialization to the Writer. If your Writer is not thread safe, // you may consider a sync wrapper. type Logger struct { @@ -188,6 +232,8 @@ type Logger struct { sampler Sampler context []byte hooks []Hook + stack bool + ctx context.Context } // New creates a root logger with given output writer. If the output writer implements @@ -195,15 +241,15 @@ type Logger struct { // one. // // Each logging operation makes a single call to the Writer's Write method. There is no -// guaranty on access serialization to the Writer. If your Writer is not thread safe, +// guarantee on access serialization to the Writer. If your Writer is not thread safe, // you may consider using sync wrapper. func New(w io.Writer) Logger { if w == nil { - w = ioutil.Discard + w = io.Discard } lw, ok := w.(LevelWriter) if !ok { - lw = levelWriterAdapter{w} + lw = LevelWriterAdapter{w} } return Logger{w: lw, level: TraceLevel} } @@ -218,6 +264,7 @@ func (l Logger) Output(w io.Writer) Logger { l2 := New(w) l2.level = l.level l2.sampler = l.sampler + l2.stack = l.stack if len(l.hooks) > 0 { l2.hooks = append(l2.hooks, l.hooks...) } @@ -234,13 +281,18 @@ func (l Logger) With() Context { l.context = make([]byte, 0, 500) if context != nil { l.context = append(l.context, context...) + } else { + // This is needed for AppendKey to not check len of input + // thus making it inlinable + l.context = enc.AppendBeginMarker(l.context) } return Context{l} } // UpdateContext updates the internal logger's context. // -// Use this method with caution. If unsure, prefer the With method. +// Caution: This method is not concurrency safe. +// Use the With method to create a child logger before modifying the context from concurrent goroutines. func (l *Logger) UpdateContext(update func(c Context) Context) { if l == disabledLogger { return @@ -248,6 +300,9 @@ func (l *Logger) UpdateContext(update func(c Context) Context) { if cap(l.context) == 0 { l.context = make([]byte, 0, 500) } + if len(l.context) == 0 { + l.context = enc.AppendBeginMarker(l.context) + } c := update(Context{*l}) l.context = c.l.context } @@ -270,8 +325,13 @@ func (l Logger) Sample(s Sampler) Logger { } // Hook returns a logger with the h Hook. -func (l Logger) Hook(h Hook) Logger { - l.hooks = append(l.hooks, h) +func (l Logger) Hook(hooks ...Hook) Logger { + if len(hooks) == 0 { + return l + } + newHooks := make([]Hook, len(l.hooks), len(l.hooks)+len(hooks)) + copy(newHooks, l.hooks) + l.hooks = append(newHooks, hooks...) return l } @@ -327,7 +387,14 @@ func (l *Logger) Err(err error) *Event { // // You must call Msg on the returned event in order to send the event. func (l *Logger) Fatal() *Event { - return l.newEvent(FatalLevel, func(msg string) { os.Exit(1) }) + return l.newEvent(FatalLevel, func(msg string) { + if closer, ok := l.w.(io.Closer); ok { + // Close the writer to flush any buffered message. Otherwise the message + // will be lost as os.Exit() terminates the program immediately. + closer.Close() + } + os.Exit(1) + }) } // Panic starts a new message with panic level. The panic() function @@ -340,7 +407,7 @@ func (l *Logger) Panic() *Event { // WithLevel starts a new message with level. Unlike Fatal and Panic // methods, WithLevel does not terminate the program or stop the ordinary -// flow of a gourotine when used with their respective levels. +// flow of a goroutine when used with their respective levels. // // You must call Msg on the returned event in order to send the event. func (l *Logger) WithLevel(level Level) *Event { @@ -364,7 +431,7 @@ func (l *Logger) WithLevel(level Level) *Event { case Disabled: return nil default: - panic("zerolog: WithLevel(): invalid level: " + strconv.Itoa(int(level))) + return l.newEvent(level, nil) } } @@ -380,7 +447,7 @@ func (l *Logger) Log() *Event { // Arguments are handled in the manner of fmt.Print. func (l *Logger) Print(v ...interface{}) { if e := l.Debug(); e.Enabled() { - e.Msg(fmt.Sprint(v...)) + e.CallerSkipFrame(1).Msg(fmt.Sprint(v...)) } } @@ -388,7 +455,15 @@ func (l *Logger) Print(v ...interface{}) { // Arguments are handled in the manner of fmt.Printf. func (l *Logger) Printf(format string, v ...interface{}) { if e := l.Debug(); e.Enabled() { - e.Msg(fmt.Sprintf(format, v...)) + e.CallerSkipFrame(1).Msg(fmt.Sprintf(format, v...)) + } +} + +// Println sends a log event using debug level and no extra field. +// Arguments are handled in the manner of fmt.Println. +func (l *Logger) Println(v ...interface{}) { + if e := l.Debug(); e.Enabled() { + e.CallerSkipFrame(1).Msg(fmt.Sprintln(v...)) } } @@ -400,29 +475,39 @@ func (l Logger) Write(p []byte) (n int, err error) { // Trim CR added by stdlog. p = p[0 : n-1] } - l.Log().Msg(string(p)) + l.Log().CallerSkipFrame(1).Msg(string(p)) return } func (l *Logger) newEvent(level Level, done func(string)) *Event { enabled := l.should(level) if !enabled { + if done != nil { + done("") + } return nil } e := newEvent(l.w, level) e.done = done e.ch = l.hooks - if level != NoLevel { + e.ctx = l.ctx + if level != NoLevel && LevelFieldName != "" { e.Str(LevelFieldName, LevelFieldMarshalFunc(level)) } - if l.context != nil && len(l.context) > 0 { + if l.context != nil && len(l.context) > 1 { e.buf = enc.AppendObjectData(e.buf, l.context) } + if l.stack { + e.Stack() + } return e } // should returns true if the log event should be logged. func (l *Logger) should(lvl Level) bool { + if l.w == nil { + return false + } if lvl < l.level || lvl < GlobalLevel() { return false } diff --git a/vendor/github.com/rs/zerolog/log/log.go b/vendor/github.com/rs/zerolog/log/log.go index b96f1c144..a96ec5067 100644 --- a/vendor/github.com/rs/zerolog/log/log.go +++ b/vendor/github.com/rs/zerolog/log/log.go @@ -3,6 +3,7 @@ package log import ( "context" + "fmt" "io" "os" @@ -114,13 +115,13 @@ func Log() *zerolog.Event { // Print sends a log event using debug level and no extra field. // Arguments are handled in the manner of fmt.Print. func Print(v ...interface{}) { - Logger.Print(v...) + Logger.Debug().CallerSkipFrame(1).Msg(fmt.Sprint(v...)) } // Printf sends a log event using debug level and no extra field. // Arguments are handled in the manner of fmt.Printf. func Printf(format string, v ...interface{}) { - Logger.Printf(format, v...) + Logger.Debug().CallerSkipFrame(1).Msgf(format, v...) } // Ctx returns the Logger associated with the ctx. If no logger diff --git a/vendor/github.com/rs/zerolog/pretty.png b/vendor/github.com/rs/zerolog/pretty.png index 34e43085ff315341b1902509f462b5e437f1304c..1449e45d142c74d023eccd28c7f9e03b0af2d2b9 100644 GIT binary patch literal 118839 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

0hOT$`donwI~(&Fqvi(oj|qzVR4* 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]V;ZJ?Jx7eS(*KURO{y5^Zh7CMY>g9 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

e|J9tMUg#4>R!uWvx3o}B=;~zVQ!`c? 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 0 { + _, origFile, origLine, _ := runtime.Caller(1) + _, frameFile, frameLine, ok := runtime.Caller(1 + t.Frame) + if ok { + erase := strings.Repeat("\b", len(path.Base(origFile))+len(strconv.Itoa(origLine))+3) + t.T.Logf("%s%s:%d: %s", erase, path.Base(frameFile), frameLine, p) + return n, err + } + } + t.T.Log(string(p)) + + return n, err +} + +// ConsoleTestWriter creates an option that correctly sets the file frame depth for testing.TB log. +func ConsoleTestWriter(t TestingLog) func(w *ConsoleWriter) { + return func(w *ConsoleWriter) { + w.Out = TestWriter{T: t, Frame: 6} + } +} + +// FilteredLevelWriter writes only logs at Level or above to Writer. +// +// It should be used only in combination with MultiLevelWriter when you +// want to write to multiple destinations at different levels. Otherwise +// you should just set the level on the logger and filter events early. +// When using MultiLevelWriter then you set the level on the logger to +// the lowest of the levels you use for writers. +type FilteredLevelWriter struct { + Writer LevelWriter + Level Level +} + +// Write writes to the underlying Writer. +func (w *FilteredLevelWriter) Write(p []byte) (int, error) { + return w.Writer.Write(p) +} + +// WriteLevel calls WriteLevel of the underlying Writer only if the level is equal +// or above the Level. +func (w *FilteredLevelWriter) WriteLevel(level Level, p []byte) (int, error) { + if level >= w.Level { + return w.Writer.WriteLevel(level, p) + } + return len(p), nil +} + +var triggerWriterPool = &sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(make([]byte, 0, 1024)) + }, +} + +// TriggerLevelWriter buffers log lines at the ConditionalLevel or below +// until a trigger level (or higher) line is emitted. Log lines with level +// higher than ConditionalLevel are always written out to the destination +// writer. If trigger never happens, buffered log lines are never written out. +// +// It can be used to configure "log level per request". +type TriggerLevelWriter struct { + // Destination writer. If LevelWriter is provided (usually), its WriteLevel is used + // instead of Write. + io.Writer + + // ConditionalLevel is the level (and below) at which lines are buffered until + // a trigger level (or higher) line is emitted. Usually this is set to DebugLevel. + ConditionalLevel Level + + // TriggerLevel is the lowest level that triggers the sending of the conditional + // level lines. Usually this is set to ErrorLevel. + TriggerLevel Level + + buf *bytes.Buffer + triggered bool + mu sync.Mutex +} + +func (w *TriggerLevelWriter) WriteLevel(l Level, p []byte) (n int, err error) { + w.mu.Lock() + defer w.mu.Unlock() + + // At first trigger level or above log line, we flush the buffer and change the + // trigger state to triggered. + if !w.triggered && l >= w.TriggerLevel { + err := w.trigger() + if err != nil { + return 0, err + } + } + + // Unless triggered, we buffer everything at and below ConditionalLevel. + if !w.triggered && l <= w.ConditionalLevel { + if w.buf == nil { + w.buf = triggerWriterPool.Get().(*bytes.Buffer) + } + + // We prefix each log line with a byte with the level. + // Hopefully we will never have a level value which equals a newline + // (which could interfere with reconstruction of log lines in the trigger method). + w.buf.WriteByte(byte(l)) + w.buf.Write(p) + return len(p), nil + } + + // Anything above ConditionalLevel is always passed through. + // Once triggered, everything is passed through. + if lw, ok := w.Writer.(LevelWriter); ok { + return lw.WriteLevel(l, p) + } + return w.Write(p) +} + +// trigger expects lock to be held. +func (w *TriggerLevelWriter) trigger() error { + if w.triggered { + return nil + } + w.triggered = true + + if w.buf == nil { + return nil + } + + p := w.buf.Bytes() + for len(p) > 0 { + // We do not use bufio.Scanner here because we already have full buffer + // in the memory and we do not want extra copying from the buffer to + // scanner's token slice, nor we want to hit scanner's token size limit, + // and we also want to preserve newlines. + i := bytes.IndexByte(p, '\n') + line := p[0 : i+1] + p = p[i+1:] + // We prefixed each log line with a byte with the level. + level := Level(line[0]) + line = line[1:] + var err error + if lw, ok := w.Writer.(LevelWriter); ok { + _, err = lw.WriteLevel(level, line) + } else { + _, err = w.Write(line) + } + if err != nil { + return err + } + } + + return nil +} + +// Trigger forces flushing the buffer and change the trigger state to +// triggered, if the writer has not already been triggered before. +func (w *TriggerLevelWriter) Trigger() error { + w.mu.Lock() + defer w.mu.Unlock() + + return w.trigger() +} + +// Close closes the writer and returns the buffer to the pool. +func (w *TriggerLevelWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.buf == nil { + return nil + } + + // We return the buffer only if it has not grown above the limit. + // This prevents accumulation of large buffers in the pool just + // because occasionally a large buffer might be needed. + if w.buf.Cap() <= TriggerLevelWriterBufferReuseLimit { + w.buf.Reset() + triggerWriterPool.Put(w.buf) + } + w.buf = nil + + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 2516fe0bd..5ad0656ef 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -600,8 +600,8 @@ github.com/quasilyte/stdinfo # github.com/rs/xid v1.5.0 ## explicit; go 1.12 github.com/rs/xid -# github.com/rs/zerolog v1.17.2 -## explicit +# github.com/rs/zerolog v1.32.0 +## explicit; go 1.15 github.com/rs/zerolog github.com/rs/zerolog/internal/cbor github.com/rs/zerolog/internal/json From e57c7b422028424ca14d0d5a995a1cb61eabaa19 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:36:52 +0200 Subject: [PATCH 20/31] gomod: Update github.com/shopspring/decimal --- go.mod | 2 +- go.sum | 4 +- .../github.com/shopspring/decimal/.gitignore | 7 + .../github.com/shopspring/decimal/.travis.yml | 11 +- .../shopspring/decimal/CHANGELOG.md | 49 ++ .../github.com/shopspring/decimal/README.md | 22 +- .../shopspring/decimal/decimal-go.go | 1 + .../github.com/shopspring/decimal/decimal.go | 584 +++++++++++++++--- .../github.com/shopspring/decimal/rounding.go | 64 +- vendor/modules.txt | 2 +- 10 files changed, 639 insertions(+), 107 deletions(-) create mode 100644 vendor/github.com/shopspring/decimal/CHANGELOG.md diff --git a/go.mod b/go.mod index 02326248e..271ba781f 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/prometheus/client_golang v1.19.0 github.com/rs/xid v1.5.0 github.com/rs/zerolog v1.32.0 - github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 + github.com/shopspring/decimal v1.3.1 github.com/sony/gobreaker v0.4.1 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 diff --git a/go.sum b/go.sum index c8af3b13c..12cf33571 100644 --- a/go.sum +++ b/go.sum @@ -583,8 +583,8 @@ github.com/securego/gosec/v2 v2.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgI github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= -github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 h1:Pm6R878vxWWWR+Sa3ppsLce/Zq+JNTs6aVvRu13jv9A= -github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= diff --git a/vendor/github.com/shopspring/decimal/.gitignore b/vendor/github.com/shopspring/decimal/.gitignore index 53579428f..ff36b987f 100644 --- a/vendor/github.com/shopspring/decimal/.gitignore +++ b/vendor/github.com/shopspring/decimal/.gitignore @@ -1,2 +1,9 @@ .git *.swp + +# IntelliJ +.idea/ +*.iml + +# VS code +*.code-workspace diff --git a/vendor/github.com/shopspring/decimal/.travis.yml b/vendor/github.com/shopspring/decimal/.travis.yml index 28f68a3a3..6326d40f0 100644 --- a/vendor/github.com/shopspring/decimal/.travis.yml +++ b/vendor/github.com/shopspring/decimal/.travis.yml @@ -1,8 +1,15 @@ language: go +arch: + - amd64 + - ppc64le + go: - - 1.2.2 - - 1.13 + - 1.7.x + - 1.14.x + - 1.15.x + - 1.16.x + - 1.17.x - tip install: diff --git a/vendor/github.com/shopspring/decimal/CHANGELOG.md b/vendor/github.com/shopspring/decimal/CHANGELOG.md new file mode 100644 index 000000000..aea61154b --- /dev/null +++ b/vendor/github.com/shopspring/decimal/CHANGELOG.md @@ -0,0 +1,49 @@ +## Decimal v1.3.1 + +#### ENHANCEMENTS +- Reduce memory allocation in case of initialization from big.Int [#252](https://github.com/shopspring/decimal/pull/252) + +#### BUGFIXES +- Fix binary marshalling of decimal zero value [#253](https://github.com/shopspring/decimal/pull/253) + +## Decimal v1.3.0 + +#### FEATURES +- Add NewFromFormattedString initializer [#184](https://github.com/shopspring/decimal/pull/184) +- Add NewNullDecimal initializer [#234](https://github.com/shopspring/decimal/pull/234) +- Add implementation of natural exponent function (Taylor, Hull-Abraham) [#229](https://github.com/shopspring/decimal/pull/229) +- Add RoundUp, RoundDown, RoundCeil, RoundFloor methods [#196](https://github.com/shopspring/decimal/pull/196) [#202](https://github.com/shopspring/decimal/pull/202) [#220](https://github.com/shopspring/decimal/pull/220) +- Add XML support for NullDecimal [#192](https://github.com/shopspring/decimal/pull/192) +- Add IsInteger method [#179](https://github.com/shopspring/decimal/pull/179) +- Add Copy helper method [#123](https://github.com/shopspring/decimal/pull/123) +- Add InexactFloat64 helper method [#205](https://github.com/shopspring/decimal/pull/205) +- Add CoefficientInt64 helper method [#244](https://github.com/shopspring/decimal/pull/244) + +#### ENHANCEMENTS +- Performance optimization of NewFromString init method [#198](https://github.com/shopspring/decimal/pull/198) +- Performance optimization of Abs and Round methods [#240](https://github.com/shopspring/decimal/pull/240) +- Additional tests (CI) for ppc64le architecture [#188](https://github.com/shopspring/decimal/pull/188) + +#### BUGFIXES +- Fix rounding in FormatFloat fallback path (roundShortest method, fix taken from Go main repository) [#161](https://github.com/shopspring/decimal/pull/161) +- Add slice range checks to UnmarshalBinary method [#232](https://github.com/shopspring/decimal/pull/232) + +## Decimal v1.2.0 + +#### BREAKING +- Drop support for Go version older than 1.7 [#172](https://github.com/shopspring/decimal/pull/172) + +#### FEATURES +- Add NewFromInt and NewFromInt32 initializers [#72](https://github.com/shopspring/decimal/pull/72) +- Add support for Go modules [#157](https://github.com/shopspring/decimal/pull/157) +- Add BigInt, BigFloat helper methods [#171](https://github.com/shopspring/decimal/pull/171) + +#### ENHANCEMENTS +- Memory usage optimization [#160](https://github.com/shopspring/decimal/pull/160) +- Updated travis CI golang versions [#156](https://github.com/shopspring/decimal/pull/156) +- Update documentation [#173](https://github.com/shopspring/decimal/pull/173) +- Improve code quality [#174](https://github.com/shopspring/decimal/pull/174) + +#### BUGFIXES +- Revert remove insignificant digits [#159](https://github.com/shopspring/decimal/pull/159) +- Remove 15 interval for RoundCash [#166](https://github.com/shopspring/decimal/pull/166) diff --git a/vendor/github.com/shopspring/decimal/README.md b/vendor/github.com/shopspring/decimal/README.md index 912d68d94..2e35df068 100644 --- a/vendor/github.com/shopspring/decimal/README.md +++ b/vendor/github.com/shopspring/decimal/README.md @@ -1,23 +1,27 @@ # decimal -[![Build Status](https://travis-ci.org/shopspring/decimal.png?branch=master)](https://travis-ci.org/shopspring/decimal) [![GoDoc](https://godoc.org/github.com/shopspring/decimal?status.svg)](https://godoc.org/github.com/shopspring/decimal) [![Go Report Card](https://goreportcard.com/badge/github.com/shopspring/decimal)](https://goreportcard.com/report/github.com/shopspring/decimal) +[![Build Status](https://app.travis-ci.com/shopspring/decimal.svg?branch=master)](https://app.travis-ci.com/shopspring/decimal) [![GoDoc](https://godoc.org/github.com/shopspring/decimal?status.svg)](https://godoc.org/github.com/shopspring/decimal) [![Go Report Card](https://goreportcard.com/badge/github.com/shopspring/decimal)](https://goreportcard.com/report/github.com/shopspring/decimal) Arbitrary-precision fixed-point decimal numbers in go. -NOTE: can "only" represent numbers with a maximum of 2^31 digits after the decimal point. +_Note:_ Decimal library can "only" represent numbers with a maximum of 2^31 digits after the decimal point. ## Features - * the zero-value is 0, and is safe to use without initialization - * addition, subtraction, multiplication with no loss of precision - * division with specified precision - * database/sql serialization/deserialization - * json and xml serialization/deserialization + * The zero-value is 0, and is safe to use without initialization + * Addition, subtraction, multiplication with no loss of precision + * Division with specified precision + * Database/sql serialization/deserialization + * JSON and XML serialization/deserialization ## Install Run `go get github.com/shopspring/decimal` +## Requirements + +Decimal library requires Go version `>=1.7` + ## Usage ```go @@ -66,8 +70,8 @@ http://godoc.org/github.com/shopspring/decimal #### Why don't you just use float64? -Because float64s (or any binary floating point type, actually) can't represent -numbers such as 0.1 exactly. +Because float64 (or any binary floating point type, actually) can't represent +numbers such as `0.1` exactly. Consider this code: http://play.golang.org/p/TQBd4yJe6B You might expect that it prints out `10`, but it actually prints `9.999999999999831`. Over time, diff --git a/vendor/github.com/shopspring/decimal/decimal-go.go b/vendor/github.com/shopspring/decimal/decimal-go.go index e08a15ce4..9958d6902 100644 --- a/vendor/github.com/shopspring/decimal/decimal-go.go +++ b/vendor/github.com/shopspring/decimal/decimal-go.go @@ -8,6 +8,7 @@ // Can do binary floating point in multiprecision decimal precisely // because 2 divides 10; cannot do decimal floating point // in multiprecision binary precisely. + package decimal type decimal struct { diff --git a/vendor/github.com/shopspring/decimal/decimal.go b/vendor/github.com/shopspring/decimal/decimal.go index 914e704ab..84405ec1c 100644 --- a/vendor/github.com/shopspring/decimal/decimal.go +++ b/vendor/github.com/shopspring/decimal/decimal.go @@ -1,11 +1,5 @@ // Package decimal implements an arbitrary precision fixed-point decimal. // -// To use as part of a struct: -// -// type Struct struct { -// Number Decimal -// } -// // The zero-value of a Decimal is 0, as you would expect. // // The best way to create a new Decimal is to use decimal.NewFromString, ex: @@ -13,8 +7,13 @@ // n, err := decimal.NewFromString("-123.4567") // n.String() // output: "-123.4567" // -// NOTE: This can "only" represent numbers with a maximum of 2^31 digits -// after the decimal point. +// To use Decimal as part of a struct: +// +// type Struct struct { +// Number Decimal +// } +// +// Note: This can "only" represent numbers with a maximum of 2^31 digits after the decimal point. package decimal import ( @@ -23,6 +22,7 @@ import ( "fmt" "math" "math/big" + "regexp" "strconv" "strings" ) @@ -32,14 +32,14 @@ import ( // // Example: // -// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3) +// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) // d1.String() // output: "0.6666666666666667" -// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000) +// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000)) // d2.String() // output: "0.0000666666666667" -// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3) +// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3)) // d3.String() // output: "6666.6666666666666667" // decimal.DivisionPrecision = 3 -// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3) +// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) // d4.String() // output: "0.667" // var DivisionPrecision = 16 @@ -52,12 +52,14 @@ var DivisionPrecision = 16 // silently lose precision. var MarshalJSONWithoutQuotes = false +// ExpMaxIterations specifies the maximum number of iterations needed to calculate +// precise natural exponent value using ExpHullAbrham method. +var ExpMaxIterations = 1000 + // Zero constant, to make computations faster. +// Zero should never be compared with == or != directly, please use decimal.Equal or decimal.Cmp instead. var Zero = New(0, 1) -// fiveDec used in Cash Rounding -var fiveDec = New(5, 0) - var zeroInt = big.NewInt(0) var oneInt = big.NewInt(1) var twoInt = big.NewInt(2) @@ -66,6 +68,8 @@ var fiveInt = big.NewInt(5) var tenInt = big.NewInt(10) var twentyInt = big.NewInt(20) +var factorials = []Decimal{New(1, 0)} + // Decimal represents a fixed-point decimal. It is immutable. // number = value * 10 ^ exp type Decimal struct { @@ -116,17 +120,19 @@ func NewFromInt32(value int32) Decimal { // NewFromBigInt returns a new Decimal from a big.Int, value * 10 ^ exp func NewFromBigInt(value *big.Int, exp int32) Decimal { return Decimal{ - value: big.NewInt(0).Set(value), + value: new(big.Int).Set(value), exp: exp, } } // NewFromString returns a new Decimal from a string representation. +// Trailing zeroes are not trimmed. // // Example: // // d, err := NewFromString("-123.45") // d2, err := NewFromString(".0001") +// d3, err := NewFromString("1.47000") // func NewFromString(value string) (Decimal, error) { originalInput := value @@ -147,28 +153,45 @@ func NewFromString(value string) (Decimal, error) { exp = expInt } - parts := strings.Split(value, ".") - if len(parts) == 1 { + pIndex := -1 + vLen := len(value) + for i := 0; i < vLen; i++ { + if value[i] == '.' { + if pIndex > -1 { + return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) + } + pIndex = i + } + } + + if pIndex == -1 { // There is no decimal point, we can just parse the original string as // an int intString = value - } else if len(parts) == 2 { - // strip the insignificant digits for more accurate comparisons. - decimalPart := strings.TrimRight(parts[1], "0") - intString = parts[0] + decimalPart - if intString == "" && parts[1] != "" { - intString = "0" + } else { + if pIndex+1 < vLen { + intString = value[:pIndex] + value[pIndex+1:] + } else { + intString = value[:pIndex] } - expInt := -len(decimalPart) + expInt := -len(value[pIndex+1:]) exp += int64(expInt) - } else { - return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) } - dValue := new(big.Int) - _, ok := dValue.SetString(intString, 10) - if !ok { - return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + var dValue *big.Int + // strconv.ParseInt is faster than new(big.Int).SetString so this is just a shortcut for strings we know won't overflow + if len(intString) <= 18 { + parsed64, err := strconv.ParseInt(intString, 10, 64) + if err != nil { + return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + } + dValue = big.NewInt(parsed64) + } else { + dValue = new(big.Int) + _, ok := dValue.SetString(intString, 10) + if !ok { + return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + } } if exp < math.MinInt32 || exp > math.MaxInt32 { @@ -182,6 +205,30 @@ func NewFromString(value string) (Decimal, error) { }, nil } +// NewFromFormattedString returns a new Decimal from a formatted string representation. +// The second argument - replRegexp, is a regular expression that is used to find characters that should be +// removed from given decimal string representation. All matched characters will be replaced with an empty string. +// +// Example: +// +// r := regexp.MustCompile("[$,]") +// d1, err := NewFromFormattedString("$5,125.99", r) +// +// r2 := regexp.MustCompile("[_]") +// d2, err := NewFromFormattedString("1_000_000", r2) +// +// r3 := regexp.MustCompile("[USD\\s]") +// d3, err := NewFromFormattedString("5000 USD", r3) +// +func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) { + parsedValue := replRegexp.ReplaceAllString(value, "") + d, err := NewFromString(parsedValue) + if err != nil { + return Decimal{}, err + } + return d, nil +} + // RequireFromString returns a new Decimal from a string representation // or panics if NewFromString would have returned an error. // @@ -215,7 +262,7 @@ func NewFromFloat(value float64) Decimal { return newFromFloat(value, math.Float64bits(value), &float64info) } -// NewFromFloat converts a float32 to Decimal. +// NewFromFloat32 converts a float32 to Decimal. // // The converted number will contain the number of significant digits that can be // represented in a float with reliable roundtrip. @@ -301,10 +348,9 @@ func NewFromFloatWithExponent(value float64, exp int32) Decimal { // specials if mant == 0 { return Decimal{} - } else { - // subnormal - exp2++ } + // subnormal + exp2++ } else { // normal mant |= 1 << 52 @@ -368,6 +414,15 @@ func NewFromFloatWithExponent(value float64, exp int32) Decimal { } } +// Copy returns a copy of decimal with the same value and exponent, but a different pointer to value. +func (d Decimal) Copy() Decimal { + d.ensureInitialized() + return Decimal{ + value: &(*d.value), + exp: d.exp, + } +} + // rescale returns a rescaled version of the decimal. Returned // decimal may be less precise if the given exponent is bigger // than the initial exponent of the Decimal. @@ -417,6 +472,9 @@ func (d Decimal) rescale(exp int32) Decimal { // Abs returns the absolute value of the decimal. func (d Decimal) Abs() Decimal { + if !d.IsNegative() { + return d + } d.ensureInitialized() d2Value := new(big.Int).Abs(d.value) return Decimal{ @@ -590,6 +648,207 @@ func (d Decimal) Pow(d2 Decimal) Decimal { return temp.Mul(temp).Div(d) } +// ExpHullAbrham calculates the natural exponent of decimal (e to the power of d) using Hull-Abraham algorithm. +// OverallPrecision argument specifies the overall precision of the result (integer part + decimal part). +// +// ExpHullAbrham is faster than ExpTaylor for small precision values, but it is much slower for large precision values. +// +// Example: +// +// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000" +// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284" +// +func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) { + // Algorithm based on Variable precision exponential function. + // ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham. + if d.IsZero() { + return Decimal{oneInt, 0}, nil + } + + currentPrecision := overallPrecision + + // Algorithm does not work if currentPrecision * 23 < |x|. + // Precision is automatically increased in such cases, so the value can be calculated precisely. + // If newly calculated precision is higher than ExpMaxIterations the currentPrecision will not be changed. + f := d.Abs().InexactFloat64() + if ncp := f / 23; ncp > float64(currentPrecision) && ncp < float64(ExpMaxIterations) { + currentPrecision = uint32(math.Ceil(ncp)) + } + + // fail if abs(d) beyond an over/underflow threshold + overflowThreshold := New(23*int64(currentPrecision), 0) + if d.Abs().Cmp(overflowThreshold) > 0 { + return Decimal{}, fmt.Errorf("over/underflow threshold, exp(x) cannot be calculated precisely") + } + + // Return 1 if abs(d) small enough; this also avoids later over/underflow + overflowThreshold2 := New(9, -int32(currentPrecision)-1) + if d.Abs().Cmp(overflowThreshold2) <= 0 { + return Decimal{oneInt, d.exp}, nil + } + + // t is the smallest integer >= 0 such that the corresponding abs(d/k) < 1 + t := d.exp + int32(d.NumDigits()) // Add d.NumDigits because the paper assumes that d.value [0.1, 1) + + if t < 0 { + t = 0 + } + + k := New(1, t) // reduction factor + r := Decimal{new(big.Int).Set(d.value), d.exp - t} // reduced argument + p := int32(currentPrecision) + t + 2 // precision for calculating the sum + + // Determine n, the number of therms for calculating sum + // use first Newton step (1.435p - 1.182) / log10(p/abs(r)) + // for solving appropriate equation, along with directed + // roundings and simple rational bound for log10(p/abs(r)) + rf := r.Abs().InexactFloat64() + pf := float64(p) + nf := math.Ceil((1.453*pf - 1.182) / math.Log10(pf/rf)) + if nf > float64(ExpMaxIterations) || math.IsNaN(nf) { + return Decimal{}, fmt.Errorf("exact value cannot be calculated in <=ExpMaxIterations iterations") + } + n := int64(nf) + + tmp := New(0, 0) + sum := New(1, 0) + one := New(1, 0) + for i := n - 1; i > 0; i-- { + tmp.value.SetInt64(i) + sum = sum.Mul(r.DivRound(tmp, p)) + sum = sum.Add(one) + } + + ki := k.IntPart() + res := New(1, 0) + for i := ki; i > 0; i-- { + res = res.Mul(sum) + } + + resNumDigits := int32(res.NumDigits()) + + var roundDigits int32 + if resNumDigits > abs(res.exp) { + roundDigits = int32(currentPrecision) - resNumDigits - res.exp + } else { + roundDigits = int32(currentPrecision) + } + + res = res.Round(roundDigits) + + return res, nil +} + +// ExpTaylor calculates the natural exponent of decimal (e to the power of d) using Taylor series expansion. +// Precision argument specifies how precise the result must be (number of digits after decimal point). +// Negative precision is allowed. +// +// ExpTaylor is much faster for large precision values than ExpHullAbrham. +// +// Example: +// +// d, err := NewFromFloat(26.1).ExpTaylor(2).String() +// d.String() // output: "216314672147.06" +// +// NewFromFloat(26.1).ExpTaylor(20).String() +// d.String() // output: "216314672147.05767284062928674083" +// +// NewFromFloat(26.1).ExpTaylor(-10).String() +// d.String() // output: "220000000000" +// +func (d Decimal) ExpTaylor(precision int32) (Decimal, error) { + // Note(mwoss): Implementation can be optimized by exclusively using big.Int API only + if d.IsZero() { + return Decimal{oneInt, 0}.Round(precision), nil + } + + var epsilon Decimal + var divPrecision int32 + if precision < 0 { + epsilon = New(1, -1) + divPrecision = 8 + } else { + epsilon = New(1, -precision-1) + divPrecision = precision + 1 + } + + decAbs := d.Abs() + pow := d.Abs() + factorial := New(1, 0) + + result := New(1, 0) + + for i := int64(1); ; { + step := pow.DivRound(factorial, divPrecision) + result = result.Add(step) + + // Stop Taylor series when current step is smaller than epsilon + if step.Cmp(epsilon) < 0 { + break + } + + pow = pow.Mul(decAbs) + + i++ + + // Calculate next factorial number or retrieve cached value + if len(factorials) >= int(i) && !factorials[i-1].IsZero() { + factorial = factorials[i-1] + } else { + // To avoid any race conditions, firstly the zero value is appended to a slice to create + // a spot for newly calculated factorial. After that, the zero value is replaced by calculated + // factorial using the index notation. + factorial = factorials[i-2].Mul(New(i, 0)) + factorials = append(factorials, Zero) + factorials[i-1] = factorial + } + } + + if d.Sign() < 0 { + result = New(1, 0).DivRound(result, precision+1) + } + + result = result.Round(precision) + return result, nil +} + +// NumDigits returns the number of digits of the decimal coefficient (d.Value) +// Note: Current implementation is extremely slow for large decimals and/or decimals with large fractional part +func (d Decimal) NumDigits() int { + // Note(mwoss): It can be optimized, unnecessary cast of big.Int to string + if d.IsNegative() { + return len(d.value.String()) - 1 + } + return len(d.value.String()) +} + +// IsInteger returns true when decimal can be represented as an integer value, otherwise, it returns false. +func (d Decimal) IsInteger() bool { + // The most typical case, all decimal with exponent higher or equal 0 can be represented as integer + if d.exp >= 0 { + return true + } + // When the exponent is negative we have to check every number after the decimal place + // If all of them are zeroes, we are sure that given decimal can be represented as an integer + var r big.Int + q := new(big.Int).Set(d.value) + for z := abs(d.exp); z > 0; z-- { + q.QuoRem(q, tenInt, &r) + if r.Cmp(zeroInt) != 0 { + return false + } + } + return true +} + +// Abs calculates absolute value of any int32. Used for calculating absolute value of decimal's exponent. +func abs(n int32) int32 { + if n < 0 { + return -n + } + return n +} + // Cmp compares the numbers represented by d and d2 and returns: // // -1 if d < d2 @@ -686,12 +945,18 @@ func (d Decimal) Exponent() int32 { return d.exp } -// Coefficient returns the coefficient of the decimal. It is scaled by 10^Exponent() +// Coefficient returns the coefficient of the decimal. It is scaled by 10^Exponent() func (d Decimal) Coefficient() *big.Int { d.ensureInitialized() - // we copy the coefficient so that mutating the result does not mutate the - // Decimal. - return big.NewInt(0).Set(d.value) + // we copy the coefficient so that mutating the result does not mutate the Decimal. + return new(big.Int).Set(d.value) +} + +// CoefficientInt64 returns the coefficient of the decimal as int64. It is scaled by 10^Exponent() +// If coefficient cannot be represented in an int64, the result will be undefined. +func (d Decimal) CoefficientInt64() int64 { + d.ensureInitialized() + return d.value.Int64() } // IntPart returns the integer component of the decimal. @@ -700,6 +965,22 @@ func (d Decimal) IntPart() int64 { return scaledD.value.Int64() } +// BigInt returns integer component of the decimal as a BigInt. +func (d Decimal) BigInt() *big.Int { + scaledD := d.rescale(0) + i := &big.Int{} + i.SetString(scaledD.String(), 10) + return i +} + +// BigFloat returns decimal as BigFloat. +// Be aware that casting decimal to BigFloat might cause a loss of precision. +func (d Decimal) BigFloat() *big.Float { + f := &big.Float{} + f.SetString(d.String()) + return f +} + // Rat returns a rational number representation of the decimal. func (d Decimal) Rat() *big.Rat { d.ensureInitialized() @@ -721,6 +1002,13 @@ func (d Decimal) Float64() (f float64, exact bool) { return d.Rat().Float64() } +// InexactFloat64 returns the nearest float64 value for d. +// It doesn't indicate if the returned value represents d exactly. +func (d Decimal) InexactFloat64() float64 { + f, _ := d.Float64() + return f +} + // String returns the string representation of the decimal // with the fixed point. // @@ -760,13 +1048,13 @@ func (d Decimal) StringFixed(places int32) string { // // Example: // -// NewFromFloat(0).StringFixed(2) // output: "0.00" -// NewFromFloat(0).StringFixed(0) // output: "0" -// NewFromFloat(5.45).StringFixed(0) // output: "5" -// NewFromFloat(5.45).StringFixed(1) // output: "5.4" -// NewFromFloat(5.45).StringFixed(2) // output: "5.45" -// NewFromFloat(5.45).StringFixed(3) // output: "5.450" -// NewFromFloat(545).StringFixed(-1) // output: "550" +// NewFromFloat(0).StringFixedBank(2) // output: "0.00" +// NewFromFloat(0).StringFixedBank(0) // output: "0" +// NewFromFloat(5.45).StringFixedBank(0) // output: "5" +// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4" +// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45" +// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450" +// NewFromFloat(545).StringFixedBank(-1) // output: "540" // func (d Decimal) StringFixedBank(places int32) string { rounded := d.RoundBank(places) @@ -789,6 +1077,9 @@ func (d Decimal) StringFixedCash(interval uint8) string { // NewFromFloat(545).Round(-1).String() // output: "550" // func (d Decimal) Round(places int32) Decimal { + if d.exp == -places { + return d + } // truncate to places + 1 ret := d.rescale(-places - 1) @@ -809,6 +1100,107 @@ func (d Decimal) Round(places int32) Decimal { return ret } +// RoundCeil rounds the decimal towards +infinity. +// +// Example: +// +// NewFromFloat(545).RoundCeil(-2).String() // output: "600" +// NewFromFloat(500).RoundCeil(-2).String() // output: "500" +// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11" +// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5" +// +func (d Decimal) RoundCeil(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() > 0 { + rescaled.value.Add(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundFloor rounds the decimal towards -infinity. +// +// Example: +// +// NewFromFloat(545).RoundFloor(-2).String() // output: "500" +// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500" +// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1" +// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4" +// +func (d Decimal) RoundFloor(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() < 0 { + rescaled.value.Sub(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundUp rounds the decimal away from zero. +// +// Example: +// +// NewFromFloat(545).RoundUp(-2).String() // output: "600" +// NewFromFloat(500).RoundUp(-2).String() // output: "500" +// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11" +// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4" +// +func (d Decimal) RoundUp(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() > 0 { + rescaled.value.Add(rescaled.value, oneInt) + } else if d.value.Sign() < 0 { + rescaled.value.Sub(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundDown rounds the decimal towards zero. +// +// Example: +// +// NewFromFloat(545).RoundDown(-2).String() // output: "500" +// NewFromFloat(-500).RoundDown(-2).String() // output: "-500" +// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1" +// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5" +// +func (d Decimal) RoundDown(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + return rescaled +} + // RoundBank rounds the decimal to places decimal places. // If the final digit to round is equidistant from the nearest two integers the // rounded value is taken as the even number @@ -817,12 +1209,12 @@ func (d Decimal) Round(places int32) Decimal { // // Examples: // -// NewFromFloat(5.45).Round(1).String() // output: "5.4" -// NewFromFloat(545).Round(-1).String() // output: "540" -// NewFromFloat(5.46).Round(1).String() // output: "5.5" -// NewFromFloat(546).Round(-1).String() // output: "550" -// NewFromFloat(5.55).Round(1).String() // output: "5.6" -// NewFromFloat(555).Round(-1).String() // output: "560" +// NewFromFloat(5.45).RoundBank(1).String() // output: "5.4" +// NewFromFloat(545).RoundBank(-1).String() // output: "540" +// NewFromFloat(5.46).RoundBank(1).String() // output: "5.5" +// NewFromFloat(546).RoundBank(-1).String() // output: "550" +// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6" +// NewFromFloat(555).RoundBank(-1).String() // output: "560" // func (d Decimal) RoundBank(places int32) Decimal { @@ -844,10 +1236,9 @@ func (d Decimal) RoundBank(places int32) Decimal { // RoundCash aka Cash/Penny/öre rounding rounds decimal to a specific // interval. The amount payable for a cash transaction is rounded to the nearest // multiple of the minimum currency unit available. The following intervals are -// available: 5, 10, 15, 25, 50 and 100; any other number throws a panic. +// available: 5, 10, 25, 50 and 100; any other number throws a panic. // 5: 5 cent rounding 3.43 => 3.45 // 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) -// 15: 10 cent rounding 3.45 => 3.40 (5 gets rounded down) // 25: 25 cent rounding 3.41 => 3.50 // 50: 50 cent rounding 3.75 => 4.00 // 100: 100 cent rounding 3.50 => 4.00 @@ -859,20 +1250,6 @@ func (d Decimal) RoundCash(interval uint8) Decimal { iVal = twentyInt case 10: iVal = tenInt - case 15: - if d.exp < 0 { - // TODO: optimize and reduce allocations - orgExp := d.exp - dOne := New(10^-int64(orgExp), orgExp) - d2 := d - d2.exp = 0 - if d2.Mod(fiveDec).Equal(Zero) { - d2.exp = orgExp - d2 = d2.Sub(dOne) - d = d2 - } - } - iVal = tenInt case 25: iVal = fourInt case 50: @@ -880,11 +1257,12 @@ func (d Decimal) RoundCash(interval uint8) Decimal { case 100: iVal = oneInt default: - panic(fmt.Sprintf("Decimal does not support this Cash rounding interval `%d`. Supported: 5, 10, 15, 25, 50, 100", interval)) + panic(fmt.Sprintf("Decimal does not support this Cash rounding interval `%d`. Supported: 5, 10, 25, 50, 100", interval)) } dVal := Decimal{ value: iVal, } + // TODO: optimize those calculations to reduce the high allocations (~29 allocs). return d.Mul(dVal).Round(0).Div(dVal).Truncate(2) } @@ -950,13 +1328,13 @@ func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error { str, err := unquoteIfQuoted(decimalBytes) if err != nil { - return fmt.Errorf("Error decoding string '%s': %s", decimalBytes, err) + return fmt.Errorf("error decoding string '%s': %s", decimalBytes, err) } decimal, err := NewFromString(str) *d = decimal if err != nil { - return fmt.Errorf("Error decoding string '%s': %s", str, err) + return fmt.Errorf("error decoding string '%s': %s", str, err) } return nil } @@ -975,12 +1353,22 @@ func (d Decimal) MarshalJSON() ([]byte, error) { // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. As a string representation // is already used when encoding to text, this method stores that string as []byte func (d *Decimal) UnmarshalBinary(data []byte) error { + // Verify we have at least 4 bytes for the exponent. The GOB encoded value + // may be empty. + if len(data) < 4 { + return fmt.Errorf("error decoding binary %v: expected at least 4 bytes, got %d", data, len(data)) + } + // Extract the exponent d.exp = int32(binary.BigEndian.Uint32(data[:4])) // Extract the value d.value = new(big.Int) - return d.value.GobDecode(data[4:]) + if err := d.value.GobDecode(data[4:]); err != nil { + return fmt.Errorf("error decoding binary %v: %s", data, err) + } + + return nil } // MarshalBinary implements the encoding.BinaryMarshaler interface. @@ -1044,7 +1432,7 @@ func (d *Decimal) UnmarshalText(text []byte) error { dec, err := NewFromString(str) *d = dec if err != nil { - return fmt.Errorf("Error decoding string '%s': %s", str, err) + return fmt.Errorf("error decoding string '%s': %s", str, err) } return nil @@ -1174,7 +1562,7 @@ func Avg(first Decimal, rest ...Decimal) Decimal { return sum.Div(count) } -// Rescale two decimals to common exponential value (minimal exp of both decimals) +// RescalePair rescales two decimals to common exponential value (minimal exp of both decimals) func RescalePair(d1 Decimal, d2 Decimal) (Decimal, Decimal) { d1.ensureInitialized() d2.ensureInitialized() @@ -1206,7 +1594,7 @@ func unquoteIfQuoted(value interface{}) (string, error) { case []byte: bytes = v default: - return "", fmt.Errorf("Could not convert value '%+v' to byte array of type '%T'", + return "", fmt.Errorf("could not convert value '%+v' to byte array of type '%T'", value, value) } @@ -1224,6 +1612,13 @@ type NullDecimal struct { Valid bool } +func NewNullDecimal(d Decimal) NullDecimal { + return NullDecimal{ + Decimal: d, + Valid: true, + } +} + // Scan implements the sql.Scanner interface for database deserialization. func (d *NullDecimal) Scan(value interface{}) error { if value == nil { @@ -1260,17 +1655,44 @@ func (d NullDecimal) MarshalJSON() ([]byte, error) { return d.Decimal.MarshalJSON() } +// UnmarshalText implements the encoding.TextUnmarshaler interface for XML +// deserialization +func (d *NullDecimal) UnmarshalText(text []byte) error { + str := string(text) + + // check for empty XML or XML without body e.g., + if str == "" { + d.Valid = false + return nil + } + if err := d.Decimal.UnmarshalText(text); err != nil { + d.Valid = false + return err + } + d.Valid = true + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface for XML +// serialization. +func (d NullDecimal) MarshalText() (text []byte, err error) { + if !d.Valid { + return []byte{}, nil + } + return d.Decimal.MarshalText() +} + // Trig functions // Atan returns the arctangent, in radians, of x. -func (x Decimal) Atan() Decimal { - if x.Equal(NewFromFloat(0.0)) { - return x +func (d Decimal) Atan() Decimal { + if d.Equal(NewFromFloat(0.0)) { + return d } - if x.GreaterThan(NewFromFloat(0.0)) { - return x.satan() + if d.GreaterThan(NewFromFloat(0.0)) { + return d.satan() } - return x.Neg().satan().Neg() + return d.Neg().satan().Neg() } func (d Decimal) xatan() Decimal { diff --git a/vendor/github.com/shopspring/decimal/rounding.go b/vendor/github.com/shopspring/decimal/rounding.go index fdd74eaa8..d4b0cd007 100644 --- a/vendor/github.com/shopspring/decimal/rounding.go +++ b/vendor/github.com/shopspring/decimal/rounding.go @@ -8,6 +8,7 @@ // Can do binary floating point in multiprecision decimal precisely // because 2 divides 10; cannot do decimal floating point // in multiprecision binary precisely. + package decimal type floatInfo struct { @@ -79,39 +80,80 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { // would round to the original mantissa and not the neighbors. inclusive := mant%2 == 0 + // As we walk the digits we want to know whether rounding up would fall + // within the upper bound. This is tracked by upperdelta: + // + // If upperdelta == 0, the digits of d and upper are the same so far. + // + // If upperdelta == 1, we saw a difference of 1 between d and upper on a + // previous digit and subsequently only 9s for d and 0s for upper. + // (Thus rounding up may fall outside the bound, if it is exclusive.) + // + // If upperdelta == 2, then the difference is greater than 1 + // and we know that rounding up falls within the bound. + var upperdelta uint8 + // Now we can figure out the minimum number of digits required. // Walk along until d has distinguished itself from upper and lower. - for i := 0; i < d.nd; i++ { + for ui := 0; ; ui++ { + // lower, d, and upper may have the decimal points at different + // places. In this case upper is the longest, so we iterate from + // ui==0 and start li and mi at (possibly) -1. + mi := ui - upper.dp + d.dp + if mi >= d.nd { + break + } + li := ui - upper.dp + lower.dp l := byte('0') // lower digit - if i < lower.nd { - l = lower.d[i] + if li >= 0 && li < lower.nd { + l = lower.d[li] + } + m := byte('0') // middle digit + if mi >= 0 { + m = d.d[mi] } - m := d.d[i] // middle digit u := byte('0') // upper digit - if i < upper.nd { - u = upper.d[i] + if ui < upper.nd { + u = upper.d[ui] } // Okay to round down (truncate) if lower has a different digit // or if lower is inclusive and is exactly the result of rounding // down (i.e., and we have reached the final digit of lower). - okdown := l != m || inclusive && i+1 == lower.nd + okdown := l != m || inclusive && li+1 == lower.nd + switch { + case upperdelta == 0 && m+1 < u: + // Example: + // m = 12345xxx + // u = 12347xxx + upperdelta = 2 + case upperdelta == 0 && m != u: + // Example: + // m = 12345xxx + // u = 12346xxx + upperdelta = 1 + case upperdelta == 1 && (m != '9' || u != '0'): + // Example: + // m = 1234598x + // u = 1234600x + upperdelta = 2 + } // Okay to round up if upper has a different digit and either upper // is inclusive or upper is bigger than the result of rounding up. - okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd) + okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd) // If it's okay to do either, then round to the nearest one. // If it's okay to do only one, do it. switch { case okdown && okup: - d.Round(i + 1) + d.Round(mi + 1) return case okdown: - d.RoundDown(i + 1) + d.RoundDown(mi + 1) return case okup: - d.RoundUp(i + 1) + d.RoundUp(mi + 1) return } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 5ad0656ef..5e5c195c8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -630,7 +630,7 @@ github.com/securego/gosec/v2/rules # github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c ## explicit github.com/shazow/go-diff/difflib -# github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 +# github.com/shopspring/decimal v1.3.1 ## explicit; go 1.13 github.com/shopspring/decimal # github.com/sirupsen/logrus v1.9.0 From f645644209655870c627c3f9b72649e1404d1055 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:37:24 +0200 Subject: [PATCH 21/31] gomod: Update github.com/sony/gobreaker --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/sony/gobreaker/.travis.yml | 15 ------ vendor/github.com/sony/gobreaker/README.md | 8 +++- vendor/github.com/sony/gobreaker/gobreaker.go | 46 +++++++++++++++++-- vendor/modules.txt | 2 +- 6 files changed, 51 insertions(+), 26 deletions(-) delete mode 100644 vendor/github.com/sony/gobreaker/.travis.yml diff --git a/go.mod b/go.mod index 271ba781f..e33c3ae82 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/rs/xid v1.5.0 github.com/rs/zerolog v1.32.0 github.com/shopspring/decimal v1.3.1 - github.com/sony/gobreaker v0.4.1 + github.com/sony/gobreaker v0.5.0 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 github.com/uber/jaeger-client-go v2.14.0+incompatible diff --git a/go.sum b/go.sum index 12cf33571..5fa1b39b0 100644 --- a/go.sum +++ b/go.sum @@ -603,8 +603,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY= github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= -github.com/sony/gobreaker v0.4.1 h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= diff --git a/vendor/github.com/sony/gobreaker/.travis.yml b/vendor/github.com/sony/gobreaker/.travis.yml deleted file mode 100644 index 6418d181d..000000000 --- a/vendor/github.com/sony/gobreaker/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go -go: - - 1.10.x - - 1.11.x - - 1.12.x -sudo: false -before_install: - - go get -u golang.org/x/lint/golint - - go get github.com/axw/gocov/gocov - - go get github.com/mattn/goveralls -script: - - test -z "`gofmt -l .`" - - test -z "`golint ./...`" - - $GOPATH/bin/goveralls -service=travis-ci - - cd example && go build -o http_breaker && ./http_breaker diff --git a/vendor/github.com/sony/gobreaker/README.md b/vendor/github.com/sony/gobreaker/README.md index ce7d7a77e..bbc23769d 100644 --- a/vendor/github.com/sony/gobreaker/README.md +++ b/vendor/github.com/sony/gobreaker/README.md @@ -2,8 +2,6 @@ gobreaker ========= [![GoDoc](https://godoc.org/github.com/sony/gobreaker?status.svg)](http://godoc.org/github.com/sony/gobreaker) -[![Build Status](https://travis-ci.org/sony/gobreaker.svg?branch=master)](https://travis-ci.org/sony/gobreaker) -[![Coverage Status](https://coveralls.io/repos/sony/gobreaker/badge.svg?branch=master&service=github)](https://coveralls.io/github/sony/gobreaker?branch=master) [gobreaker][repo-url] implements the [Circuit Breaker pattern](https://msdn.microsoft.com/en-us/library/dn589784.aspx) in Go. @@ -34,6 +32,7 @@ type Settings struct { Timeout time.Duration ReadyToTrip func(counts Counts) bool OnStateChange func(name string, from State, to State) + IsSuccessful func(err error) bool } ``` @@ -58,6 +57,11 @@ type Settings struct { - `OnStateChange` is called whenever the state of `CircuitBreaker` changes. +- `IsSuccessful` is called with the error returned from a request. + If `IsSuccessful` returns true, the error is counted as a success. + Otherwise the error is counted as a failure. + If `IsSuccessful` is nil, default `IsSuccessful` is used, which returns false for all non-nil errors. + The struct `Counts` holds the numbers of requests and their successes/failures: ```go diff --git a/vendor/github.com/sony/gobreaker/gobreaker.go b/vendor/github.com/sony/gobreaker/gobreaker.go index faea65882..7503a278b 100644 --- a/vendor/github.com/sony/gobreaker/gobreaker.go +++ b/vendor/github.com/sony/gobreaker/gobreaker.go @@ -86,11 +86,11 @@ func (c *Counts) clear() { // // Interval is the cyclic period of the closed state // for the CircuitBreaker to clear the internal Counts. -// If Interval is 0, the CircuitBreaker doesn't clear internal Counts during the closed state. +// If Interval is less than or equal to 0, the CircuitBreaker doesn't clear internal Counts during the closed state. // // Timeout is the period of the open state, // after which the state of the CircuitBreaker becomes half-open. -// If Timeout is 0, the timeout value of the CircuitBreaker is set to 60 seconds. +// If Timeout is less than or equal to 0, the timeout value of the CircuitBreaker is set to 60 seconds. // // ReadyToTrip is called with a copy of Counts whenever a request fails in the closed state. // If ReadyToTrip returns true, the CircuitBreaker will be placed into the open state. @@ -98,6 +98,11 @@ func (c *Counts) clear() { // Default ReadyToTrip returns true when the number of consecutive failures is more than 5. // // OnStateChange is called whenever the state of the CircuitBreaker changes. +// +// IsSuccessful is called with the error returned from a request. +// If IsSuccessful returns true, the error is counted as a success. +// Otherwise the error is counted as a failure. +// If IsSuccessful is nil, default IsSuccessful is used, which returns false for all non-nil errors. type Settings struct { Name string MaxRequests uint32 @@ -105,6 +110,7 @@ type Settings struct { Timeout time.Duration ReadyToTrip func(counts Counts) bool OnStateChange func(name string, from State, to State) + IsSuccessful func(err error) bool } // CircuitBreaker is a state machine to prevent sending requests that are likely to fail. @@ -114,6 +120,7 @@ type CircuitBreaker struct { interval time.Duration timeout time.Duration readyToTrip func(counts Counts) bool + isSuccessful func(err error) bool onStateChange func(name string, from State, to State) mutex sync.Mutex @@ -135,7 +142,6 @@ func NewCircuitBreaker(st Settings) *CircuitBreaker { cb := new(CircuitBreaker) cb.name = st.Name - cb.interval = st.Interval cb.onStateChange = st.OnStateChange if st.MaxRequests == 0 { @@ -144,7 +150,13 @@ func NewCircuitBreaker(st Settings) *CircuitBreaker { cb.maxRequests = st.MaxRequests } - if st.Timeout == 0 { + if st.Interval <= 0 { + cb.interval = defaultInterval + } else { + cb.interval = st.Interval + } + + if st.Timeout <= 0 { cb.timeout = defaultTimeout } else { cb.timeout = st.Timeout @@ -156,6 +168,12 @@ func NewCircuitBreaker(st Settings) *CircuitBreaker { cb.readyToTrip = st.ReadyToTrip } + if st.IsSuccessful == nil { + cb.isSuccessful = defaultIsSuccessful + } else { + cb.isSuccessful = st.IsSuccessful + } + cb.toNewGeneration(time.Now()) return cb @@ -168,12 +186,17 @@ func NewTwoStepCircuitBreaker(st Settings) *TwoStepCircuitBreaker { } } +const defaultInterval = time.Duration(0) * time.Second const defaultTimeout = time.Duration(60) * time.Second func defaultReadyToTrip(counts Counts) bool { return counts.ConsecutiveFailures > 5 } +func defaultIsSuccessful(err error) bool { + return err == nil +} + // Name returns the name of the CircuitBreaker. func (cb *CircuitBreaker) Name() string { return cb.name @@ -189,6 +212,14 @@ func (cb *CircuitBreaker) State() State { return state } +// Counts returns internal counters +func (cb *CircuitBreaker) Counts() Counts { + cb.mutex.Lock() + defer cb.mutex.Unlock() + + return cb.counts +} + // Execute runs the given request if the CircuitBreaker accepts it. // Execute returns an error instantly if the CircuitBreaker rejects the request. // Otherwise, Execute returns the result of the request. @@ -209,7 +240,7 @@ func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, }() result, err := req() - cb.afterRequest(generation, err == nil) + cb.afterRequest(generation, cb.isSuccessful(err)) return result, err } @@ -223,6 +254,11 @@ func (tscb *TwoStepCircuitBreaker) State() State { return tscb.cb.State() } +// Counts returns internal counters +func (tscb *TwoStepCircuitBreaker) Counts() Counts { + return tscb.cb.Counts() +} + // Allow checks if a new request can proceed. It returns a callback that should be used to // register the success or failure in a separate step. If the circuit breaker doesn't allow // requests, it returns an error. diff --git a/vendor/modules.txt b/vendor/modules.txt index 5e5c195c8..2fada1eb0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -650,7 +650,7 @@ github.com/sivchari/tenv github.com/sonatard/noctx github.com/sonatard/noctx/ngfunc github.com/sonatard/noctx/reqwithoutctx -# github.com/sony/gobreaker v0.4.1 +# github.com/sony/gobreaker v0.5.0 ## explicit; go 1.12 github.com/sony/gobreaker # github.com/sourcegraph/go-diff v0.7.0 From 505435215e7665472f6c25387ad6a8356f1a2d4c Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:37:54 +0200 Subject: [PATCH 22/31] gomod: Update github.com/spf13/cobra --- go.mod | 4 +- go.sum | 10 +- .../inconshreveable/mousetrap/trap_others.go | 1 + .../inconshreveable/mousetrap/trap_windows.go | 88 +-- .../mousetrap/trap_windows_1.4.go | 46 -- vendor/github.com/spf13/cobra/.golangci.yml | 10 +- vendor/github.com/spf13/cobra/Makefile | 8 +- vendor/github.com/spf13/cobra/README.md | 12 +- vendor/github.com/spf13/cobra/active_help.go | 12 +- vendor/github.com/spf13/cobra/active_help.md | 157 ---- vendor/github.com/spf13/cobra/args.go | 4 +- .../spf13/cobra/bash_completions.go | 6 +- .../spf13/cobra/bash_completions.md | 93 --- .../spf13/cobra/bash_completionsV2.go | 73 +- vendor/github.com/spf13/cobra/cobra.go | 19 +- vendor/github.com/spf13/cobra/command.go | 123 +++- .../github.com/spf13/cobra/command_notwin.go | 2 +- vendor/github.com/spf13/cobra/command_win.go | 2 +- vendor/github.com/spf13/cobra/completions.go | 42 +- .../spf13/cobra/fish_completions.go | 78 +- .../spf13/cobra/fish_completions.md | 4 - vendor/github.com/spf13/cobra/flag_groups.go | 70 +- .../spf13/cobra/powershell_completions.go | 31 +- .../spf13/cobra/powershell_completions.md | 3 - .../spf13/cobra/projects_using_cobra.md | 60 -- .../spf13/cobra/shell_completions.go | 2 +- .../spf13/cobra/shell_completions.md | 568 -------------- vendor/github.com/spf13/cobra/user_guide.md | 695 ------------------ .../github.com/spf13/cobra/zsh_completions.go | 17 +- .../github.com/spf13/cobra/zsh_completions.md | 48 -- vendor/modules.txt | 4 +- 31 files changed, 418 insertions(+), 1874 deletions(-) delete mode 100644 vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go delete mode 100644 vendor/github.com/spf13/cobra/active_help.md delete mode 100644 vendor/github.com/spf13/cobra/bash_completions.md delete mode 100644 vendor/github.com/spf13/cobra/fish_completions.md delete mode 100644 vendor/github.com/spf13/cobra/powershell_completions.md delete mode 100644 vendor/github.com/spf13/cobra/projects_using_cobra.md delete mode 100644 vendor/github.com/spf13/cobra/shell_completions.md delete mode 100644 vendor/github.com/spf13/cobra/user_guide.md delete mode 100644 vendor/github.com/spf13/cobra/zsh_completions.md diff --git a/go.mod b/go.mod index e33c3ae82..9424f4c56 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/rs/zerolog v1.32.0 github.com/shopspring/decimal v1.3.1 github.com/sony/gobreaker v0.5.0 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.2 github.com/uber/jaeger-client-go v2.14.0+incompatible github.com/uber/jaeger-lib v1.5.0 @@ -119,7 +119,7 @@ require ( github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jgautheron/goconst v1.5.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect diff --git a/go.sum b/go.sum index 5fa1b39b0..574fb6e64 100644 --- a/go.sum +++ b/go.sum @@ -128,7 +128,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/daixiang0/gci v0.9.1 h1:jBrwBmBZTDsGsXiaCTLIe9diotp1X4X64zodFrh7l+c= @@ -365,8 +365,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= @@ -611,8 +611,8 @@ github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go index 9d2d8a4ba..06a91f086 100644 --- a/vendor/github.com/inconshreveable/mousetrap/trap_others.go +++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package mousetrap diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go index 336142a5e..0c5688021 100644 --- a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go @@ -1,81 +1,32 @@ -// +build windows -// +build !go1.4 - package mousetrap import ( - "fmt" - "os" "syscall" "unsafe" ) -const ( - // defined by the Win32 API - th32cs_snapprocess uintptr = 0x2 -) - -var ( - kernel = syscall.MustLoadDLL("kernel32.dll") - CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") - Process32First = kernel.MustFindProc("Process32FirstW") - Process32Next = kernel.MustFindProc("Process32NextW") -) - -// ProcessEntry32 structure defined by the Win32 API -type processEntry32 struct { - dwSize uint32 - cntUsage uint32 - th32ProcessID uint32 - th32DefaultHeapID int - th32ModuleID uint32 - cntThreads uint32 - th32ParentProcessID uint32 - pcPriClassBase int32 - dwFlags uint32 - szExeFile [syscall.MAX_PATH]uint16 -} - -func getProcessEntry(pid int) (pe *processEntry32, err error) { - snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) - if snapshot == uintptr(syscall.InvalidHandle) { - err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) - return +func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { + snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err } - defer syscall.CloseHandle(syscall.Handle(snapshot)) - - var processEntry processEntry32 - processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) - ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) - if ok == 0 { - err = fmt.Errorf("Process32First: %v", e1) - return + defer syscall.CloseHandle(snapshot) + var procEntry syscall.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = syscall.Process32First(snapshot, &procEntry); err != nil { + return nil, err } - for { - if processEntry.th32ProcessID == uint32(pid) { - pe = &processEntry - return + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil } - - ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) - if ok == 0 { - err = fmt.Errorf("Process32Next: %v", e1) - return + err = syscall.Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err } } } -func getppid() (pid int, err error) { - pe, err := getProcessEntry(os.Getpid()) - if err != nil { - return - } - - pid = int(pe.th32ParentProcessID) - return -} - // StartedByExplorer returns true if the program was invoked by the user double-clicking // on the executable from explorer.exe // @@ -83,16 +34,9 @@ func getppid() (pid int, err error) { // It does not guarantee that the program was run from a terminal. It only can tell you // whether it was launched from explorer.exe func StartedByExplorer() bool { - ppid, err := getppid() + pe, err := getProcessEntry(syscall.Getppid()) if err != nil { return false } - - pe, err := getProcessEntry(ppid) - if err != nil { - return false - } - - name := syscall.UTF16ToString(pe.szExeFile[:]) - return name == "explorer.exe" + return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) } diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go deleted file mode 100644 index 9a28e57c3..000000000 --- a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build windows -// +build go1.4 - -package mousetrap - -import ( - "os" - "syscall" - "unsafe" -) - -func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { - snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) - if err != nil { - return nil, err - } - defer syscall.CloseHandle(snapshot) - var procEntry syscall.ProcessEntry32 - procEntry.Size = uint32(unsafe.Sizeof(procEntry)) - if err = syscall.Process32First(snapshot, &procEntry); err != nil { - return nil, err - } - for { - if procEntry.ProcessID == uint32(pid) { - return &procEntry, nil - } - err = syscall.Process32Next(snapshot, &procEntry) - if err != nil { - return nil, err - } - } -} - -// StartedByExplorer returns true if the program was invoked by the user double-clicking -// on the executable from explorer.exe -// -// It is conservative and returns false if any of the internal calls fail. -// It does not guarantee that the program was run from a terminal. It only can tell you -// whether it was launched from explorer.exe -func StartedByExplorer() bool { - pe, err := getProcessEntry(os.Getppid()) - if err != nil { - return false - } - return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) -} diff --git a/vendor/github.com/spf13/cobra/.golangci.yml b/vendor/github.com/spf13/cobra/.golangci.yml index 439d3e1de..a618ec24d 100644 --- a/vendor/github.com/spf13/cobra/.golangci.yml +++ b/vendor/github.com/spf13/cobra/.golangci.yml @@ -1,4 +1,4 @@ -# Copyright 2013-2022 The Cobra Authors +# Copyright 2013-2023 The Cobra Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ linters: disable-all: true enable: #- bodyclose - - deadcode + # - deadcode ! deprecated since v1.49.0; replaced by 'unused' #- depguard #- dogsled #- dupl @@ -51,12 +51,12 @@ linters: #- rowserrcheck #- scopelint #- staticcheck - - structcheck + #- structcheck ! deprecated since v1.49.0; replaced by 'unused' #- stylecheck #- typecheck - unconvert #- unparam - #- unused - - varcheck + - unused + # - varcheck ! deprecated since v1.49.0; replaced by 'unused' #- whitespace fast: false diff --git a/vendor/github.com/spf13/cobra/Makefile b/vendor/github.com/spf13/cobra/Makefile index c433a01bc..0da8d7aa0 100644 --- a/vendor/github.com/spf13/cobra/Makefile +++ b/vendor/github.com/spf13/cobra/Makefile @@ -5,10 +5,6 @@ ifeq (, $(shell which golangci-lint)) $(warning "could not find golangci-lint in $(PATH), run: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh") endif -ifeq (, $(shell which richgo)) -$(warning "could not find richgo in $(PATH), run: go install github.com/kyoh86/richgo@latest") -endif - .PHONY: fmt lint test install_deps clean default: all @@ -25,6 +21,10 @@ lint: test: install_deps $(info ******************** running tests ********************) + go test -v ./... + +richtest: install_deps + $(info ******************** running tests with kyoh86/richgo ********************) richgo test -v ./... install_deps: diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 7cc726beb..6444f4b7f 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,12 +1,12 @@ -![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) +![cobra logo](assets/CobraMain.png) Cobra is a library for creating powerful modern CLI applications. Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/), [Hugo](https://gohugo.io), and [GitHub CLI](https://github.com/cli/cli) to -name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra. +name a few. [This list](site/content/projects_using_cobra.md) contains a more extensive list of projects using Cobra. -[![](https://img.shields.io/github/workflow/status/spf13/cobra/Test?longCache=tru&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest) +[![](https://img.shields.io/github/actions/workflow/status/spf13/cobra/test.yml?branch=main&longCache=true&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest) [![Go Reference](https://pkg.go.dev/badge/github.com/spf13/cobra.svg)](https://pkg.go.dev/github.com/spf13/cobra) [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra) [![Slack](https://img.shields.io/badge/Slack-cobra-brightgreen)](https://gophers.slack.com/archives/CD3LP1199) @@ -80,7 +80,7 @@ which maintains the same interface while adding POSIX compliance. # Installing Using Cobra is easy. First, use `go get` to install the latest version -of the library. +of the library. ``` go get -u github.com/spf13/cobra@latest @@ -105,8 +105,8 @@ go install github.com/spf13/cobra-cli@latest For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) -For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md). +For complete details on using the Cobra library, please read the [The Cobra User Guide](site/content/user_guide.md). # License -Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt) +Cobra is released under the Apache 2.0 license. See [LICENSE.txt](LICENSE.txt) diff --git a/vendor/github.com/spf13/cobra/active_help.go b/vendor/github.com/spf13/cobra/active_help.go index 95e03aecb..5f965e057 100644 --- a/vendor/github.com/spf13/cobra/active_help.go +++ b/vendor/github.com/spf13/cobra/active_help.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package cobra import ( "fmt" "os" + "regexp" "strings" ) @@ -29,6 +30,8 @@ const ( activeHelpGlobalDisable = "0" ) +var activeHelpEnvVarPrefixSubstRegexp = regexp.MustCompile(`[^A-Z0-9_]`) + // AppendActiveHelp adds the specified string to the specified array to be used as ActiveHelp. // Such strings will be processed by the completion script and will be shown as ActiveHelp // to the user. @@ -42,7 +45,7 @@ func AppendActiveHelp(compArray []string, activeHelpStr string) []string { // GetActiveHelpConfig returns the value of the ActiveHelp environment variable // _ACTIVE_HELP where is the name of the root command in upper -// case, with all - replaced by _. +// case, with all non-ASCII-alphanumeric characters replaced by `_`. // It will always return "0" if the global environment variable COBRA_ACTIVE_HELP // is set to "0". func GetActiveHelpConfig(cmd *Command) string { @@ -55,9 +58,10 @@ func GetActiveHelpConfig(cmd *Command) string { // activeHelpEnvVar returns the name of the program-specific ActiveHelp environment // variable. It has the format _ACTIVE_HELP where is the name of the -// root command in upper case, with all - replaced by _. +// root command in upper case, with all non-ASCII-alphanumeric characters replaced by `_`. func activeHelpEnvVar(name string) string { // This format should not be changed: users will be using it explicitly. activeHelpEnvVar := strings.ToUpper(fmt.Sprintf("%s%s", name, activeHelpEnvVarSuffix)) - return strings.ReplaceAll(activeHelpEnvVar, "-", "_") + activeHelpEnvVar = activeHelpEnvVarPrefixSubstRegexp.ReplaceAllString(activeHelpEnvVar, "_") + return activeHelpEnvVar } diff --git a/vendor/github.com/spf13/cobra/active_help.md b/vendor/github.com/spf13/cobra/active_help.md deleted file mode 100644 index 5e7f59af3..000000000 --- a/vendor/github.com/spf13/cobra/active_help.md +++ /dev/null @@ -1,157 +0,0 @@ -# Active Help - -Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion. - -For example, -``` -bash-5.1$ helm repo add [tab] -You must choose a name for the repo you are adding. - -bash-5.1$ bin/helm package [tab] -Please specify the path to the chart to package - -bash-5.1$ bin/helm package [tab][tab] -bin/ internal/ scripts/ pkg/ testdata/ -``` - -**Hint**: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program. -## Supported shells - -Active Help is currently only supported for the following shells: -- Bash (using [bash completion V2](shell_completions.md#bash-completion-v2) only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed. -- Zsh - -## Adding Active Help messages - -As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to [Shell Completions](shell_completions.md). - -Adding Active Help is done through the use of the `cobra.AppendActiveHelp(...)` function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details. - -### Active Help for nouns - -Adding Active Help when completing a noun is done within the `ValidArgsFunction(...)` of a command. Please notice the use of `cobra.AppendActiveHelp(...)` in the following example: - -```go -cmd := &cobra.Command{ - Use: "add [NAME] [URL]", - Short: "add a chart repository", - Args: require.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - return addRepo(args) - }, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - var comps []string - if len(args) == 0 { - comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding") - } else if len(args) == 1 { - comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding") - } else { - comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments") - } - return comps, cobra.ShellCompDirectiveNoFileComp - }, -} -``` -The example above defines the completions (none, in this specific example) as well as the Active Help messages for the `helm repo add` command. It yields the following behavior: -``` -bash-5.1$ helm repo add [tab] -You must choose a name for the repo you are adding - -bash-5.1$ helm repo add grafana [tab] -You must specify the URL for the repo you are adding - -bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab] -This command does not take any more arguments -``` -**Hint**: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions. - -### Active Help for flags - -Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example: -```go -_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 2 { - return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp - } - return compVersionFlag(args[1], toComplete) - }) -``` -The example above prints an Active Help message when not enough information was given by the user to complete the `--version` flag. -``` -bash-5.1$ bin/helm install myrelease --version 2.0.[tab] -You must first specify the chart to install before the --version flag can be completed - -bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab] -2.0.1 2.0.2 2.0.3 -``` - -## User control of Active Help - -You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. -Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration. - -The way to configure Active Help is to use the program's Active Help environment -variable. That variable is named `_ACTIVE_HELP` where `` is the name of your -program in uppercase with any `-` replaced by an `_`. The variable should be set by the user to whatever -Active Help configuration values are supported by the program. - -For example, say `helm` has chosen to support three levels for Active Help: `on`, `off`, `local`. Then a user -would set the desired behavior to `local` by doing `export HELM_ACTIVE_HELP=local` in their shell. - -For simplicity, when in `cmd.ValidArgsFunction(...)` or a flag's completion function, the program should read the -Active Help configuration using the `cobra.GetActiveHelpConfig(cmd)` function and select what Active Help messages -should or should not be added (instead of reading the environment variable directly). - -For example: -```go -ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - activeHelpLevel := cobra.GetActiveHelpConfig(cmd) - - var comps []string - if len(args) == 0 { - if activeHelpLevel != "off" { - comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding") - } - } else if len(args) == 1 { - if activeHelpLevel != "off" { - comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding") - } - } else { - if activeHelpLevel == "local" { - comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments") - } - } - return comps, cobra.ShellCompDirectiveNoFileComp -}, -``` -**Note 1**: If the `_ACTIVE_HELP` environment variable is set to the string "0", Cobra will automatically disable all Active Help output (even if some output was specified by the program using the `cobra.AppendActiveHelp(...)` function). Using "0" can simplify your code in situations where you want to blindly disable Active Help without having to call `cobra.GetActiveHelpConfig(cmd)` explicitly. - -**Note 2**: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable `COBRA_ACTIVE_HELP` to "0". In this case `cobra.GetActiveHelpConfig(cmd)` will return "0" no matter what the variable `_ACTIVE_HELP` is set to. - -**Note 3**: If the user does not set `_ACTIVE_HELP` or `COBRA_ACTIVE_HELP` (which will be a common case), the default value for the Active Help configuration returned by `cobra.GetActiveHelpConfig(cmd)` will be the empty string. -## Active Help with Cobra's default completion command - -Cobra provides a default `completion` command for programs that wish to use it. -When using the default `completion` command, Active Help is configurable in the same -fashion as described above using environment variables. You may wish to document this in more -details for your users. - -## Debugging Active Help - -Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra's hidden `__complete` command. Please refer to [debugging shell completion](shell_completions.md#debugging) for details. - -When debugging with the `__complete` command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named `_ACTIVE_HELP` where any `-` is replaced by an `_`. For example, we can test deactivating some Active Help as shown below: -``` -$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h -bitnami/haproxy -bitnami/harbor -_activeHelp_ WARNING: cannot re-use a name that is still in use -:0 -Completion ended with directive: ShellCompDirectiveDefault - -$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h -bitnami/haproxy -bitnami/harbor -:0 -Completion ended with directive: ShellCompDirectiveDefault -``` diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go index 2c1f99e78..e79ec33a8 100644 --- a/vendor/github.com/spf13/cobra/args.go +++ b/vendor/github.com/spf13/cobra/args.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( type PositionalArgs func(cmd *Command, args []string) error -// Legacy arg validation has the following behaviour: +// legacyArgs validation has the following behaviour: // - root commands with no subcommands can take arbitrary arguments // - root commands with subcommands will do subcommand validity checking // - subcommands will always accept arbitrary arguments diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index 3acdb2797..8a5315184 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -85,7 +85,7 @@ __%[1]s_handle_go_custom_completion() local out requestComp lastParam lastChar comp directive args # Prepare the command to request completions for the program. - # Calling ${words[0]} instead of directly %[1]s allows to handle aliases + # Calling ${words[0]} instead of directly %[1]s allows handling aliases args=("${words[@]:1}") # Disable ActiveHelp which is not supported for bash completion v1 requestComp="%[8]s=0 ${words[0]} %[2]s ${args[*]}" @@ -532,7 +532,7 @@ func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) { } } -// Setup annotations for go completions for registered flags +// prepareCustomAnnotationsForFlags setup annotations for go completions for registered flags func prepareCustomAnnotationsForFlags(cmd *Command) { flagCompletionMutex.RLock() defer flagCompletionMutex.RUnlock() diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md deleted file mode 100644 index 52919b2fa..000000000 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ /dev/null @@ -1,93 +0,0 @@ -# Generating Bash Completions For Your cobra.Command - -Please refer to [Shell Completions](shell_completions.md) for details. - -## Bash legacy dynamic completions - -For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the `ValidArgsFunction` solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side `ValidArgsFunction` and `RegisterFlagCompletionFunc()`, as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution. - -**Note**: Cobra's default `completion` command uses bash completion V2. If you are currently using Cobra's legacy dynamic completion solution, you should not use the default `completion` command but continue using your own. - -The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions. - -Some code that works in kubernetes: - -```bash -const ( - bash_completion_func = `__kubectl_parse_get() -{ - local kubectl_output out - if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then - out=($(echo "${kubectl_output}" | awk '{print $1}')) - COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) - fi -} - -__kubectl_get_resource() -{ - if [[ ${#nouns[@]} -eq 0 ]]; then - return 1 - fi - __kubectl_parse_get ${nouns[${#nouns[@]} -1]} - if [[ $? -eq 0 ]]; then - return 0 - fi -} - -__kubectl_custom_func() { - case ${last_command} in - kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) - __kubectl_get_resource - return - ;; - *) - ;; - esac -} -`) -``` - -And then I set that in my command definition: - -```go -cmds := &cobra.Command{ - Use: "kubectl", - Short: "kubectl controls the Kubernetes cluster manager", - Long: `kubectl controls the Kubernetes cluster manager. - -Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, - Run: runHelp, - BashCompletionFunction: bash_completion_func, -} -``` - -The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`___custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! - -Similarly, for flags: - -```go - annotation := make(map[string][]string) - annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} - - flag := &pflag.Flag{ - Name: "namespace", - Usage: usage, - Annotations: annotation, - } - cmd.Flags().AddFlag(flag) -``` - -In addition add the `__kubectl_get_namespaces` implementation in the `BashCompletionFunction` -value, e.g.: - -```bash -__kubectl_get_namespaces() -{ - local template - template="{{ range .items }}{{ .metadata.name }} {{ end }}" - local kubectl_out - if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then - COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) ) - fi -} -``` diff --git a/vendor/github.com/spf13/cobra/bash_completionsV2.go b/vendor/github.com/spf13/cobra/bash_completionsV2.go index bb4b71892..1cce5c329 100644 --- a/vendor/github.com/spf13/cobra/bash_completionsV2.go +++ b/vendor/github.com/spf13/cobra/bash_completionsV2.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ func genBashComp(buf io.StringWriter, name string, includeDesc bool) { __%[1]s_debug() { - if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then + if [[ -n ${BASH_COMP_DEBUG_FILE-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } @@ -57,7 +57,7 @@ __%[1]s_get_completion_results() { local requestComp lastParam lastChar args # Prepare the command to request completions for the program. - # Calling ${words[0]} instead of directly %[1]s allows to handle aliases + # Calling ${words[0]} instead of directly %[1]s allows handling aliases args=("${words[@]:1}") requestComp="${words[0]} %[2]s ${args[*]}" @@ -65,7 +65,7 @@ __%[1]s_get_completion_results() { lastChar=${lastParam:$((${#lastParam}-1)):1} __%[1]s_debug "lastParam ${lastParam}, lastChar ${lastChar}" - if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then + if [[ -z ${cur} && ${lastChar} != = ]]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" @@ -75,7 +75,7 @@ __%[1]s_get_completion_results() { # When completing a flag with an = (e.g., %[1]s -n=) # bash focuses on the part after the =, so we need to remove # the flag part from $cur - if [[ "${cur}" == -*=* ]]; then + if [[ ${cur} == -*=* ]]; then cur="${cur#*=}" fi @@ -87,7 +87,7 @@ __%[1]s_get_completion_results() { directive=${out##*:} # Remove the directive out=${out%%:*} - if [ "${directive}" = "${out}" ]; then + if [[ ${directive} == "${out}" ]]; then # There is not directive specified directive=0 fi @@ -101,22 +101,36 @@ __%[1]s_process_completion_results() { local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d + local shellCompDirectiveKeepOrder=%[8]d - if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + if (((directive & shellCompDirectiveError) != 0)); then # Error code. No completion. __%[1]s_debug "Received error from custom completion go code" return else - if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then + if (((directive & shellCompDirectiveNoSpace) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then __%[1]s_debug "Activating no space" compopt -o nospace else __%[1]s_debug "No space directive not supported in this version of bash" fi fi - if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then + if (((directive & shellCompDirectiveKeepOrder) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then + # no sort isn't supported for bash less than < 4.4 + if [[ ${BASH_VERSINFO[0]} -lt 4 || ( ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 4 ) ]]; then + __%[1]s_debug "No sort directive not supported in this version of bash" + else + __%[1]s_debug "Activating keep order" + compopt -o nosort + fi + else + __%[1]s_debug "No sort directive not supported in this version of bash" + fi + fi + if (((directive & shellCompDirectiveNoFileComp) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then __%[1]s_debug "Activating no file completion" compopt +o default else @@ -130,7 +144,7 @@ __%[1]s_process_completion_results() { local activeHelp=() __%[1]s_extract_activeHelp - if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + if (((directive & shellCompDirectiveFilterFileExt) != 0)); then # File extension filtering local fullFilter filter filteringCmd @@ -143,13 +157,12 @@ __%[1]s_process_completion_results() { filteringCmd="_filedir $fullFilter" __%[1]s_debug "File filtering command: $filteringCmd" $filteringCmd - elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + elif (((directive & shellCompDirectiveFilterDirs) != 0)); then # File completion for directories only - # Use printf to strip any trailing newline local subdir - subdir=$(printf "%%s" "${completions[0]}") - if [ -n "$subdir" ]; then + subdir=${completions[0]} + if [[ -n $subdir ]]; then __%[1]s_debug "Listing directories in $subdir" pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return else @@ -164,7 +177,7 @@ __%[1]s_process_completion_results() { __%[1]s_handle_special_char "$cur" = # Print the activeHelp statements before we finish - if [ ${#activeHelp[*]} -ne 0 ]; then + if ((${#activeHelp[*]} != 0)); then printf "\n"; printf "%%s\n" "${activeHelp[@]}" printf "\n" @@ -184,21 +197,21 @@ __%[1]s_process_completion_results() { # Separate activeHelp lines from real completions. # Fills the $activeHelp and $completions arrays. __%[1]s_extract_activeHelp() { - local activeHelpMarker="%[8]s" + local activeHelpMarker="%[9]s" local endIndex=${#activeHelpMarker} while IFS='' read -r comp; do - if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then + if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then comp=${comp:endIndex} __%[1]s_debug "ActiveHelp found: $comp" - if [ -n "$comp" ]; then + if [[ -n $comp ]]; then activeHelp+=("$comp") fi else # Not an activeHelp line but a normal completion completions+=("$comp") fi - done < <(printf "%%s\n" "${out}") + done <<<"${out}" } __%[1]s_handle_completion_types() { @@ -254,7 +267,7 @@ __%[1]s_handle_standard_completion_case() { done < <(printf "%%s\n" "${completions[@]}") # If there is a single completion left, remove the description text - if [ ${#COMPREPLY[*]} -eq 1 ]; then + if ((${#COMPREPLY[*]} == 1)); then __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" comp="${COMPREPLY[0]%%%%$tab*}" __%[1]s_debug "Removed description from single completion, which is now: ${comp}" @@ -271,8 +284,8 @@ __%[1]s_handle_special_char() if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then local word=${comp%%"${comp##*${char}}"} local idx=${#COMPREPLY[*]} - while [[ $((--idx)) -ge 0 ]]; do - COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + while ((--idx >= 0)); do + COMPREPLY[idx]=${COMPREPLY[idx]#"$word"} done fi } @@ -298,7 +311,7 @@ __%[1]s_format_comp_descriptions() # Make sure we can fit a description of at least 8 characters # if we are to align the descriptions. - if [[ $maxdesclength -gt 8 ]]; then + if ((maxdesclength > 8)); then # Add the proper number of spaces to align the descriptions for ((i = ${#comp} ; i < longest ; i++)); do comp+=" " @@ -310,8 +323,8 @@ __%[1]s_format_comp_descriptions() # If there is enough space for any description text, # truncate the descriptions that are too long for the shell width - if [ $maxdesclength -gt 0 ]; then - if [ ${#desc} -gt $maxdesclength ]; then + if ((maxdesclength > 0)); then + if ((${#desc} > maxdesclength)); then desc=${desc:0:$(( maxdesclength - 1 ))} desc+="…" fi @@ -332,9 +345,9 @@ __start_%[1]s() # Call _init_completion from the bash-completion package # to prepare the arguments properly if declare -F _init_completion >/dev/null 2>&1; then - _init_completion -n "=:" || return + _init_completion -n =: || return else - __%[1]s_init_completion -n "=:" || return + __%[1]s_init_completion -n =: || return fi __%[1]s_debug @@ -361,7 +374,7 @@ fi # ex: ts=4 sw=4 et filetype=sh `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpMarker)) } diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index fe44bc8a0..a6b160ce5 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -43,12 +43,13 @@ var initializers []func() var finalizers []func() const ( - defaultPrefixMatching = false - defaultCommandSorting = true - defaultCaseInsensitive = false + defaultPrefixMatching = false + defaultCommandSorting = true + defaultCaseInsensitive = false + defaultTraverseRunHooks = false ) -// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing +// EnablePrefixMatching allows setting automatic prefix matching. Automatic prefix matching can be a dangerous thing // to automatically enable in CLI tools. // Set this to true to enable it. var EnablePrefixMatching = defaultPrefixMatching @@ -60,6 +61,10 @@ var EnableCommandSorting = defaultCommandSorting // EnableCaseInsensitive allows case-insensitive commands names. (case sensitive by default) var EnableCaseInsensitive = defaultCaseInsensitive +// EnableTraverseRunHooks executes persistent pre-run and post-run hooks from all parents. +// By default this is disabled, which means only the first run hook to be found is executed. +var EnableTraverseRunHooks = defaultTraverseRunHooks + // MousetrapHelpText enables an information splash screen on Windows // if the CLI is started from explorer.exe. // To disable the mousetrap, just set this variable to blank string (""). @@ -167,8 +172,8 @@ func appendIfNotPresent(s, stringToAppend string) string { // rpad adds padding to the right of a string. func rpad(s string, padding int) string { - template := fmt.Sprintf("%%-%ds", padding) - return fmt.Sprintf(template, s) + formattedString := fmt.Sprintf("%%-%ds", padding) + return fmt.Sprintf(formattedString, s) } // tmpl executes the given template text on data, writing the result to w. diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 6ff47dd5c..2fbe6c131 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,12 +30,15 @@ import ( flag "github.com/spf13/pflag" ) -const FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra" +const ( + FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra" + CommandDisplayNameAnnotation = "cobra_annotation_command_display_name" +) // FParseErrWhitelist configures Flag parse errors to be ignored type FParseErrWhitelist flag.ParseErrorsWhitelist -// Structure to manage groups for commands +// Group Structure to manage groups for commands type Group struct { ID string Title string @@ -47,7 +50,7 @@ type Group struct { // definition to ensure usability. type Command struct { // Use is the one-line usage message. - // Recommended syntax is as follow: + // Recommended syntax is as follows: // [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required. // ... indicates that you can specify multiple values for the previous argument. // | indicates mutually exclusive information. You can use the argument to the left of the separator or the @@ -99,7 +102,7 @@ type Command struct { Deprecated string // Annotations are key/value pairs that can be used by applications to identify or - // group commands. + // group commands or set special options. Annotations map[string]string // Version defines the version for this command. If this value is non-empty and the command does not @@ -115,6 +118,8 @@ type Command struct { // * PostRun() // * PersistentPostRun() // All functions get the same args, the arguments after the command name. + // The *PreRun and *PostRun functions will only be executed if the Run function of the current + // command has been declared. // // PersistentPreRun: children of this command will inherit and execute. PersistentPreRun func(cmd *Command, args []string) @@ -181,6 +186,9 @@ type Command struct { // versionTemplate is the version template defined by user. versionTemplate string + // errPrefix is the error message prefix defined by user. + errPrefix string + // inReader is a reader defined by the user that replaces stdin inReader io.Reader // outWriter is a writer defined by the user that replaces stdout @@ -321,7 +329,7 @@ func (c *Command) SetHelpCommand(cmd *Command) { c.helpCommand = cmd } -// SetHelpCommandGroup sets the group id of the help command. +// SetHelpCommandGroupID sets the group id of the help command. func (c *Command) SetHelpCommandGroupID(groupID string) { if c.helpCommand != nil { c.helpCommand.GroupID = groupID @@ -330,7 +338,7 @@ func (c *Command) SetHelpCommandGroupID(groupID string) { c.helpCommandGroupID = groupID } -// SetCompletionCommandGroup sets the group id of the completion command. +// SetCompletionCommandGroupID sets the group id of the completion command. func (c *Command) SetCompletionCommandGroupID(groupID string) { // completionCommandGroupID is used if no completion command is defined by the user c.Root().completionCommandGroupID = groupID @@ -346,6 +354,11 @@ func (c *Command) SetVersionTemplate(s string) { c.versionTemplate = s } +// SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix. +func (c *Command) SetErrPrefix(s string) { + c.errPrefix = s +} + // SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. // The user should not have a cyclic dependency on commands. func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) { @@ -595,6 +608,18 @@ func (c *Command) VersionTemplate() string { ` } +// ErrPrefix return error message prefix for the command +func (c *Command) ErrPrefix() string { + if c.errPrefix != "" { + return c.errPrefix + } + + if c.HasParent() { + return c.parent.ErrPrefix() + } + return "Error:" +} + func hasNoOptDefVal(name string, fs *flag.FlagSet) bool { flag := fs.Lookup(name) if flag == nil { @@ -655,20 +680,44 @@ Loop: // argsMinusFirstX removes only the first x from args. Otherwise, commands that look like // openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). -func argsMinusFirstX(args []string, x string) []string { - for i, y := range args { - if x == y { - ret := []string{} - ret = append(ret, args[:i]...) - ret = append(ret, args[i+1:]...) - return ret +// Special care needs to be taken not to remove a flag value. +func (c *Command) argsMinusFirstX(args []string, x string) []string { + if len(args) == 0 { + return args + } + c.mergePersistentFlags() + flags := c.Flags() + +Loop: + for pos := 0; pos < len(args); pos++ { + s := args[pos] + switch { + case s == "--": + // -- means we have reached the end of the parseable args. Break out of the loop now. + break Loop + case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): + fallthrough + case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): + // This is a flag without a default value, and an equal sign is not used. Increment pos in order to skip + // over the next arg, because that is the value of this flag. + pos++ + continue + case !strings.HasPrefix(s, "-"): + // This is not a flag or a flag value. Check to see if it matches what we're looking for, and if so, + // return the args, excluding the one at this position. + if s == x { + ret := []string{} + ret = append(ret, args[:pos]...) + ret = append(ret, args[pos+1:]...) + return ret + } } } return args } func isFlagArg(arg string) bool { - return ((len(arg) >= 3 && arg[1] == '-') || + return ((len(arg) >= 3 && arg[0:2] == "--") || (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) } @@ -686,7 +735,7 @@ func (c *Command) Find(args []string) (*Command, []string, error) { cmd := c.findNext(nextSubCmd) if cmd != nil { - return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) + return innerfind(cmd, c.argsMinusFirstX(innerArgs, nextSubCmd)) } return c, innerArgs } @@ -728,7 +777,9 @@ func (c *Command) findNext(next string) *Command { } if len(matches) == 1 { - return matches[0] + // Temporarily disable gosec G602, which produces a false positive. + // See https://github.com/securego/gosec/issues/1005. + return matches[0] // #nosec G602 } return nil @@ -886,15 +937,31 @@ func (c *Command) execute(a []string) (err error) { return err } + parents := make([]*Command, 0, 5) for p := c; p != nil; p = p.Parent() { + if EnableTraverseRunHooks { + // When EnableTraverseRunHooks is set: + // - Execute all persistent pre-runs from the root parent till this command. + // - Execute all persistent post-runs from this command till the root parent. + parents = append([]*Command{p}, parents...) + } else { + // Otherwise, execute only the first found persistent hook. + parents = append(parents, p) + } + } + for _, p := range parents { if p.PersistentPreRunE != nil { if err := p.PersistentPreRunE(c, argWoFlags); err != nil { return err } - break + if !EnableTraverseRunHooks { + break + } } else if p.PersistentPreRun != nil { p.PersistentPreRun(c, argWoFlags) - break + if !EnableTraverseRunHooks { + break + } } } if c.PreRunE != nil { @@ -931,10 +998,14 @@ func (c *Command) execute(a []string) (err error) { if err := p.PersistentPostRunE(c, argWoFlags); err != nil { return err } - break + if !EnableTraverseRunHooks { + break + } } else if p.PersistentPostRun != nil { p.PersistentPostRun(c, argWoFlags) - break + if !EnableTraverseRunHooks { + break + } } } @@ -1024,7 +1095,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { c = cmd } if !c.SilenceErrors { - c.PrintErrln("Error:", err.Error()) + c.PrintErrln(c.ErrPrefix(), err.Error()) c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath()) } return c, err @@ -1053,7 +1124,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { // If root command has SilenceErrors flagged, // all subcommands should respect it if !cmd.SilenceErrors && !c.SilenceErrors { - c.PrintErrln("Error:", err.Error()) + c.PrintErrln(cmd.ErrPrefix(), err.Error()) } // If root command has SilenceUsage flagged, @@ -1272,7 +1343,7 @@ func (c *Command) AllChildCommandsHaveGroup() bool { return true } -// ContainGroups return if groupID exists in the list of command groups. +// ContainsGroup return if groupID exists in the list of command groups. func (c *Command) ContainsGroup(groupID string) bool { for _, x := range c.commandgroups { if x.ID == groupID { @@ -1356,6 +1427,9 @@ func (c *Command) CommandPath() string { if c.HasParent() { return c.Parent().CommandPath() + " " + c.Name() } + if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok { + return displayName + } return c.Name() } @@ -1378,6 +1452,7 @@ func (c *Command) UseLine() string { // DebugFlags used to determine which flags have been assigned to which commands // and which persist. +// nolint:goconst func (c *Command) DebugFlags() { c.Println("DebugFlags called on", c.Name()) var debugflags func(*Command) diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go index 2b77f8f01..307f0c127 100644 --- a/vendor/github.com/spf13/cobra/command_notwin.go +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go index 520f23abf..adbef395c 100644 --- a/vendor/github.com/spf13/cobra/command_win.go +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/completions.go b/vendor/github.com/spf13/cobra/completions.go index e8a0206db..b60f6b200 100644 --- a/vendor/github.com/spf13/cobra/completions.go +++ b/vendor/github.com/spf13/cobra/completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -77,6 +77,10 @@ const ( // obtain the same behavior but only for flags. ShellCompDirectiveFilterDirs + // ShellCompDirectiveKeepOrder indicates that the shell should preserve the order + // in which the completions are provided + ShellCompDirectiveKeepOrder + // =========================================================================== // All directives using iota should be above this one. @@ -141,6 +145,20 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman return nil } +// GetFlagCompletionFunc returns the completion function for the given flag of the command, if available. +func (c *Command) GetFlagCompletionFunc(flagName string) (func(*Command, []string, string) ([]string, ShellCompDirective), bool) { + flag := c.Flag(flagName) + if flag == nil { + return nil, false + } + + flagCompletionMutex.RLock() + defer flagCompletionMutex.RUnlock() + + completionFunc, exists := flagCompletionFunctions[flag] + return completionFunc, exists +} + // Returns a string listing the different directive enabled in the specified parameter func (d ShellCompDirective) string() string { var directives []string @@ -159,6 +177,9 @@ func (d ShellCompDirective) string() string { if d&ShellCompDirectiveFilterDirs != 0 { directives = append(directives, "ShellCompDirectiveFilterDirs") } + if d&ShellCompDirectiveKeepOrder != 0 { + directives = append(directives, "ShellCompDirectiveKeepOrder") + } if len(directives) == 0 { directives = append(directives, "ShellCompDirectiveDefault") } @@ -169,7 +190,7 @@ func (d ShellCompDirective) string() string { return strings.Join(directives, ", ") } -// Adds a special hidden command that can be used to request custom completions. +// initCompleteCmd adds a special hidden command that can be used to request custom completions. func (c *Command) initCompleteCmd(args []string) { completeCmd := &Command{ Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd), @@ -276,9 +297,13 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi // These flags are normally added when `execute()` is called on `finalCmd`, // however, when doing completion, we don't call `finalCmd.execute()`. - // Let's add the --help and --version flag ourselves. - finalCmd.InitDefaultHelpFlag() - finalCmd.InitDefaultVersionFlag() + // Let's add the --help and --version flag ourselves but only if the finalCmd + // has not disabled flag parsing; if flag parsing is disabled, it is up to the + // finalCmd itself to handle the completion of *all* flags. + if !finalCmd.DisableFlagParsing { + finalCmd.InitDefaultHelpFlag() + finalCmd.InitDefaultVersionFlag() + } // Check if we are doing flag value completion before parsing the flags. // This is important because if we are completing a flag value, we need to also @@ -382,6 +407,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) { doCompleteFlags(flag) }) + // Try to complete non-inherited flags even if DisableFlagParsing==true. + // This allows programs to tell Cobra about flags for completion even + // if the actual parsing of flags is not done by Cobra. + // For instance, Helm uses this to provide flag name completion for + // some of its plugins. finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { doCompleteFlags(flag) }) @@ -727,7 +757,7 @@ to enable it. You can execute the following once: To load completions in your current shell session: - source <(%[1]s completion zsh); compdef _%[1]s %[1]s + source <(%[1]s completion zsh) To load completions for every new session, execute once: diff --git a/vendor/github.com/spf13/cobra/fish_completions.go b/vendor/github.com/spf13/cobra/fish_completions.go index 97112a17b..12d61b691 100644 --- a/vendor/github.com/spf13/cobra/fish_completions.go +++ b/vendor/github.com/spf13/cobra/fish_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ function __%[1]s_perform_completion __%[1]s_debug "last arg: $lastArg" # Disable ActiveHelp which is not supported for fish shell - set -l requestComp "%[9]s=0 $args[1] %[3]s $args[2..-1] $lastArg" + set -l requestComp "%[10]s=0 $args[1] %[3]s $args[2..-1] $lastArg" __%[1]s_debug "Calling $requestComp" set -l results (eval $requestComp 2> /dev/null) @@ -89,6 +89,60 @@ function __%[1]s_perform_completion printf "%%s\n" "$directiveLine" end +# this function limits calls to __%[1]s_perform_completion, by caching the result behind $__%[1]s_perform_completion_once_result +function __%[1]s_perform_completion_once + __%[1]s_debug "Starting __%[1]s_perform_completion_once" + + if test -n "$__%[1]s_perform_completion_once_result" + __%[1]s_debug "Seems like a valid result already exists, skipping __%[1]s_perform_completion" + return 0 + end + + set --global __%[1]s_perform_completion_once_result (__%[1]s_perform_completion) + if test -z "$__%[1]s_perform_completion_once_result" + __%[1]s_debug "No completions, probably due to a failure" + return 1 + end + + __%[1]s_debug "Performed completions and set __%[1]s_perform_completion_once_result" + return 0 +end + +# this function is used to clear the $__%[1]s_perform_completion_once_result variable after completions are run +function __%[1]s_clear_perform_completion_once_result + __%[1]s_debug "" + __%[1]s_debug "========= clearing previously set __%[1]s_perform_completion_once_result variable ==========" + set --erase __%[1]s_perform_completion_once_result + __%[1]s_debug "Successfully erased the variable __%[1]s_perform_completion_once_result" +end + +function __%[1]s_requires_order_preservation + __%[1]s_debug "" + __%[1]s_debug "========= checking if order preservation is required ==========" + + __%[1]s_perform_completion_once + if test -z "$__%[1]s_perform_completion_once_result" + __%[1]s_debug "Error determining if order preservation is required" + return 1 + end + + set -l directive (string sub --start 2 $__%[1]s_perform_completion_once_result[-1]) + __%[1]s_debug "Directive is: $directive" + + set -l shellCompDirectiveKeepOrder %[9]d + set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) %% 2) + __%[1]s_debug "Keeporder is: $keeporder" + + if test $keeporder -ne 0 + __%[1]s_debug "This does require order preservation" + return 0 + end + + __%[1]s_debug "This doesn't require order preservation" + return 1 +end + + # This function does two things: # - Obtain the completions and store them in the global __%[1]s_comp_results # - Return false if file completion should be performed @@ -99,17 +153,17 @@ function __%[1]s_prepare_completions # Start fresh set --erase __%[1]s_comp_results - set -l results (__%[1]s_perform_completion) - __%[1]s_debug "Completion results: $results" + __%[1]s_perform_completion_once + __%[1]s_debug "Completion results: $__%[1]s_perform_completion_once_result" - if test -z "$results" + if test -z "$__%[1]s_perform_completion_once_result" __%[1]s_debug "No completion, probably due to a failure" # Might as well do file completion, in case it helps return 1 end - set -l directive (string sub --start 2 $results[-1]) - set --global __%[1]s_comp_results $results[1..-2] + set -l directive (string sub --start 2 $__%[1]s_perform_completion_once_result[-1]) + set --global __%[1]s_comp_results $__%[1]s_perform_completion_once_result[1..-2] __%[1]s_debug "Completions are: $__%[1]s_comp_results" __%[1]s_debug "Directive is: $directive" @@ -205,13 +259,17 @@ end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c %[2]s -e +# this will get called after the two calls below and clear the $__%[1]s_perform_completion_once_result global +complete -c %[2]s -n '__%[1]s_clear_perform_completion_once_result' # The call to __%[1]s_prepare_completions will setup __%[1]s_comp_results # which provides the program's completion choices. -complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' - +# If this doesn't require order preservation, we don't use the -k flag +complete -c %[2]s -n 'not __%[1]s_requires_order_preservation && __%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' +# otherwise we use the -k flag +complete -k -c %[2]s -n '__%[1]s_requires_order_preservation && __%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' `, nameForVar, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name))) } // GenFishCompletion generates fish completion file and writes to the passed writer. diff --git a/vendor/github.com/spf13/cobra/fish_completions.md b/vendor/github.com/spf13/cobra/fish_completions.md deleted file mode 100644 index 19b2ed129..000000000 --- a/vendor/github.com/spf13/cobra/fish_completions.md +++ /dev/null @@ -1,4 +0,0 @@ -## Generating Fish Completions For Your cobra.Command - -Please refer to [Shell Completions](shell_completions.md) for details. - diff --git a/vendor/github.com/spf13/cobra/flag_groups.go b/vendor/github.com/spf13/cobra/flag_groups.go index 9c377aaf9..0671ec5f2 100644 --- a/vendor/github.com/spf13/cobra/flag_groups.go +++ b/vendor/github.com/spf13/cobra/flag_groups.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import ( const ( requiredAsGroup = "cobra_annotation_required_if_others_set" + oneRequired = "cobra_annotation_one_required" mutuallyExclusive = "cobra_annotation_mutually_exclusive" ) @@ -43,6 +44,22 @@ func (c *Command) MarkFlagsRequiredTogether(flagNames ...string) { } } +// MarkFlagsOneRequired marks the given flags with annotations so that Cobra errors +// if the command is invoked without at least one flag from the given set of flags. +func (c *Command) MarkFlagsOneRequired(flagNames ...string) { + c.mergePersistentFlags() + for _, v := range flagNames { + f := c.Flags().Lookup(v) + if f == nil { + panic(fmt.Sprintf("Failed to find flag %q and mark it as being in a one-required flag group", v)) + } + if err := c.Flags().SetAnnotation(v, oneRequired, append(f.Annotations[oneRequired], strings.Join(flagNames, " "))); err != nil { + // Only errs if the flag isn't found. + panic(err) + } + } +} + // MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors // if the command is invoked with more than one flag from the given set of flags. func (c *Command) MarkFlagsMutuallyExclusive(flagNames ...string) { @@ -59,7 +76,7 @@ func (c *Command) MarkFlagsMutuallyExclusive(flagNames ...string) { } } -// ValidateFlagGroups validates the mutuallyExclusive/requiredAsGroup logic and returns the +// ValidateFlagGroups validates the mutuallyExclusive/oneRequired/requiredAsGroup logic and returns the // first error encountered. func (c *Command) ValidateFlagGroups() error { if c.DisableFlagParsing { @@ -71,15 +88,20 @@ func (c *Command) ValidateFlagGroups() error { // groupStatus format is the list of flags as a unique ID, // then a map of each flag name and whether it is set or not. groupStatus := map[string]map[string]bool{} + oneRequiredGroupStatus := map[string]map[string]bool{} mutuallyExclusiveGroupStatus := map[string]map[string]bool{} flags.VisitAll(func(pflag *flag.Flag) { processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus) + processFlagForGroupAnnotation(flags, pflag, oneRequired, oneRequiredGroupStatus) processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus) }) if err := validateRequiredFlagGroups(groupStatus); err != nil { return err } + if err := validateOneRequiredFlagGroups(oneRequiredGroupStatus); err != nil { + return err + } if err := validateExclusiveFlagGroups(mutuallyExclusiveGroupStatus); err != nil { return err } @@ -142,6 +164,27 @@ func validateRequiredFlagGroups(data map[string]map[string]bool) error { return nil } +func validateOneRequiredFlagGroups(data map[string]map[string]bool) error { + keys := sortedKeys(data) + for _, flagList := range keys { + flagnameAndStatus := data[flagList] + var set []string + for flagname, isSet := range flagnameAndStatus { + if isSet { + set = append(set, flagname) + } + } + if len(set) >= 1 { + continue + } + + // Sort values, so they can be tested/scripted against consistently. + sort.Strings(set) + return fmt.Errorf("at least one of the flags in the group [%v] is required", flagList) + } + return nil +} + func validateExclusiveFlagGroups(data map[string]map[string]bool) error { keys := sortedKeys(data) for _, flagList := range keys { @@ -176,6 +219,7 @@ func sortedKeys(m map[string]map[string]bool) []string { // enforceFlagGroupsForCompletion will do the following: // - when a flag in a group is present, other flags in the group will be marked required +// - when none of the flags in a one-required group are present, all flags in the group will be marked required // - when a flag in a mutually exclusive group is present, other flags in the group will be marked as hidden // This allows the standard completion logic to behave appropriately for flag groups func (c *Command) enforceFlagGroupsForCompletion() { @@ -185,9 +229,11 @@ func (c *Command) enforceFlagGroupsForCompletion() { flags := c.Flags() groupStatus := map[string]map[string]bool{} + oneRequiredGroupStatus := map[string]map[string]bool{} mutuallyExclusiveGroupStatus := map[string]map[string]bool{} c.Flags().VisitAll(func(pflag *flag.Flag) { processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus) + processFlagForGroupAnnotation(flags, pflag, oneRequired, oneRequiredGroupStatus) processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus) }) @@ -204,6 +250,26 @@ func (c *Command) enforceFlagGroupsForCompletion() { } } + // If none of the flags of a one-required group are present, we make all the flags + // of that group required so that the shell completion suggests them automatically + for flagList, flagnameAndStatus := range oneRequiredGroupStatus { + set := 0 + + for _, isSet := range flagnameAndStatus { + if isSet { + set++ + } + } + + // None of the flags of the group are set, mark all flags in the group + // as required + if set == 0 { + for _, fName := range strings.Split(flagList, " ") { + _ = c.MarkFlagRequired(fName) + } + } + } + // If a flag that is mutually exclusive to others is present, we hide the other // flags of that group so the shell completion does not suggest them for flagList, flagnameAndStatus := range mutuallyExclusiveGroupStatus { diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go index 004de42e4..551951939 100644 --- a/vendor/github.com/spf13/cobra/powershell_completions.go +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -47,7 +47,7 @@ filter __%[1]s_escapeStringWithSpecialChars { `+" $_ -replace '\\s|#|@|\\$|;|,|''|\\{|\\}|\\(|\\)|\"|`|\\||<|>|&','`$&'"+` } -[scriptblock]$__%[2]sCompleterBlock = { +[scriptblock]${__%[2]sCompleterBlock} = { param( $WordToComplete, $CommandAst, @@ -77,6 +77,7 @@ filter __%[1]s_escapeStringWithSpecialChars { $ShellCompDirectiveNoFileComp=%[6]d $ShellCompDirectiveFilterFileExt=%[7]d $ShellCompDirectiveFilterDirs=%[8]d + $ShellCompDirectiveKeepOrder=%[9]d # Prepare the command to request completions for the program. # Split the command at the first space to separate the program and arguments. @@ -106,13 +107,22 @@ filter __%[1]s_escapeStringWithSpecialChars { # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" -`+" # We need to use `\"`\" to pass an empty argument a \"\" or '' does not work!!!"+` -`+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+` + # PowerShell 7.2+ changed the way how the arguments are passed to executables, + # so for pre-7.2 or when Legacy argument passing is enabled we need to use +`+" # `\"`\" to pass an empty argument, a \"\" or '' does not work!!!"+` + if ($PSVersionTable.PsVersion -lt [version]'7.2.0' -or + ($PSVersionTable.PsVersion -lt [version]'7.3.0' -and -not [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -or + (($PSVersionTable.PsVersion -ge [version]'7.3.0' -or [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -and + $PSNativeCommandArgumentPassing -eq 'Legacy')) { +`+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+` + } else { + $RequestComp="$RequestComp" + ' ""' + } } __%[1]s_debug "Calling $RequestComp" # First disable ActiveHelp which is not supported for Powershell - $env:%[9]s=0 + ${env:%[10]s}=0 #call the command store the output in $out and redirect stderr and stdout to null # $Out is an array contains each line per element @@ -137,7 +147,7 @@ filter __%[1]s_escapeStringWithSpecialChars { } $Longest = 0 - $Values = $Out | ForEach-Object { + [Array]$Values = $Out | ForEach-Object { #Split the output in name and description `+" $Name, $Description = $_.Split(\"`t\",2)"+` __%[1]s_debug "Name: $Name Description: $Description" @@ -182,6 +192,11 @@ filter __%[1]s_escapeStringWithSpecialChars { } } + # we sort the values in ascending order by name if keep order isn't passed + if (($Directive -band $ShellCompDirectiveKeepOrder) -eq 0 ) { + $Values = $Values | Sort-Object -Property Name + } + if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { __%[1]s_debug "ShellCompDirectiveNoFileComp is called" @@ -264,10 +279,10 @@ filter __%[1]s_escapeStringWithSpecialChars { } } -Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock $__%[2]sCompleterBlock +Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock ${__%[2]sCompleterBlock} `, name, nameForVar, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name))) } func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error { diff --git a/vendor/github.com/spf13/cobra/powershell_completions.md b/vendor/github.com/spf13/cobra/powershell_completions.md deleted file mode 100644 index c449f1e5c..000000000 --- a/vendor/github.com/spf13/cobra/powershell_completions.md +++ /dev/null @@ -1,3 +0,0 @@ -# Generating PowerShell Completions For Your Own cobra.Command - -Please refer to [Shell Completions](shell_completions.md#powershell-completions) for details. diff --git a/vendor/github.com/spf13/cobra/projects_using_cobra.md b/vendor/github.com/spf13/cobra/projects_using_cobra.md deleted file mode 100644 index 6865f88e7..000000000 --- a/vendor/github.com/spf13/cobra/projects_using_cobra.md +++ /dev/null @@ -1,60 +0,0 @@ -## Projects using Cobra - -- [Allero](https://github.com/allero-io/allero) -- [Arduino CLI](https://github.com/arduino/arduino-cli) -- [Bleve](https://blevesearch.com/) -- [Cilium](https://cilium.io/) -- [CloudQuery](https://github.com/cloudquery/cloudquery) -- [CockroachDB](https://www.cockroachlabs.com/) -- [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) -- [Datree](https://github.com/datreeio/datree) -- [Delve](https://github.com/derekparker/delve) -- [Docker (distribution)](https://github.com/docker/distribution) -- [Etcd](https://etcd.io/) -- [Gardener](https://github.com/gardener/gardenctl) -- [Giant Swarm's gsctl](https://github.com/giantswarm/gsctl) -- [Git Bump](https://github.com/erdaltsksn/git-bump) -- [GitHub CLI](https://github.com/cli/cli) -- [GitHub Labeler](https://github.com/erdaltsksn/gh-label) -- [Golangci-lint](https://golangci-lint.run) -- [GopherJS](https://github.com/gopherjs/gopherjs) -- [GoReleaser](https://goreleaser.com) -- [Helm](https://helm.sh) -- [Hugo](https://gohugo.io) -- [Infracost](https://github.com/infracost/infracost) -- [Istio](https://istio.io) -- [Kool](https://github.com/kool-dev/kool) -- [Kubernetes](https://kubernetes.io/) -- [Kubescape](https://github.com/armosec/kubescape) -- [KubeVirt](https://github.com/kubevirt/kubevirt) -- [Linkerd](https://linkerd.io/) -- [Mattermost-server](https://github.com/mattermost/mattermost-server) -- [Mercure](https://mercure.rocks/) -- [Meroxa CLI](https://github.com/meroxa/cli) -- [Metal Stack CLI](https://github.com/metal-stack/metalctl) -- [Moby (former Docker)](https://github.com/moby/moby) -- [Moldy](https://github.com/Moldy-Community/moldy) -- [Multi-gitter](https://github.com/lindell/multi-gitter) -- [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) -- [nFPM](https://nfpm.goreleaser.com) -- [Okteto](https://github.com/okteto/okteto) -- [OpenShift](https://www.openshift.com/) -- [Ory Hydra](https://github.com/ory/hydra) -- [Ory Kratos](https://github.com/ory/kratos) -- [Pixie](https://github.com/pixie-io/pixie) -- [Polygon Edge](https://github.com/0xPolygon/polygon-edge) -- [Pouch](https://github.com/alibaba/pouch) -- [ProjectAtomic (enterprise)](https://www.projectatomic.io/) -- [Prototool](https://github.com/uber/prototool) -- [Pulumi](https://www.pulumi.com) -- [QRcp](https://github.com/claudiodangelis/qrcp) -- [Random](https://github.com/erdaltsksn/random) -- [Rclone](https://rclone.org/) -- [Scaleway CLI](https://github.com/scaleway/scaleway-cli) -- [Skaffold](https://skaffold.dev/) -- [Tendermint](https://github.com/tendermint/tendermint) -- [Twitch CLI](https://github.com/twitchdev/twitch-cli) -- [UpCloud CLI (`upctl`)](https://github.com/UpCloudLtd/upcloud-cli) -- VMware's [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) & [Tanzu Framework](https://github.com/vmware-tanzu/tanzu-framework) -- [Werf](https://werf.io/) -- [ZITADEL](https://github.com/zitadel/zitadel) diff --git a/vendor/github.com/spf13/cobra/shell_completions.go b/vendor/github.com/spf13/cobra/shell_completions.go index 126e83c30..b035742d3 100644 --- a/vendor/github.com/spf13/cobra/shell_completions.go +++ b/vendor/github.com/spf13/cobra/shell_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/shell_completions.md b/vendor/github.com/spf13/cobra/shell_completions.md deleted file mode 100644 index 553ee5df8..000000000 --- a/vendor/github.com/spf13/cobra/shell_completions.md +++ /dev/null @@ -1,568 +0,0 @@ -# Generating shell completions - -Cobra can generate shell completions for multiple shells. -The currently supported shells are: -- Bash -- Zsh -- fish -- PowerShell - -Cobra will automatically provide your program with a fully functional `completion` command, -similarly to how it provides the `help` command. - -## Creating your own completion command - -If you do not wish to use the default `completion` command, you can choose to -provide your own, which will take precedence over the default one. (This also provides -backwards-compatibility with programs that already have their own `completion` command.) - -If you are using the `cobra-cli` generator, -which can be found at [spf13/cobra-cli](https://github.com/spf13/cobra-cli), -you can create a completion command by running - -```bash -cobra-cli add completion -``` -and then modifying the generated `cmd/completion.go` file to look something like this -(writing the shell script to stdout allows the most flexible use): - -```go -var completionCmd = &cobra.Command{ - Use: "completion [bash|zsh|fish|powershell]", - Short: "Generate completion script", - Long: fmt.Sprintf(`To load completions: - -Bash: - - $ source <(%[1]s completion bash) - - # To load completions for each session, execute once: - # Linux: - $ %[1]s completion bash > /etc/bash_completion.d/%[1]s - # macOS: - $ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s - -Zsh: - - # If shell completion is not already enabled in your environment, - # you will need to enable it. You can execute the following once: - - $ echo "autoload -U compinit; compinit" >> ~/.zshrc - - # To load completions for each session, execute once: - $ %[1]s completion zsh > "${fpath[1]}/_%[1]s" - - # You will need to start a new shell for this setup to take effect. - -fish: - - $ %[1]s completion fish | source - - # To load completions for each session, execute once: - $ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish - -PowerShell: - - PS> %[1]s completion powershell | Out-String | Invoke-Expression - - # To load completions for every new session, run: - PS> %[1]s completion powershell > %[1]s.ps1 - # and source this file from your PowerShell profile. -`,cmd.Root().Name()), - DisableFlagsInUseLine: true, - ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, - Args: cobra.ExactValidArgs(1), - Run: func(cmd *cobra.Command, args []string) { - switch args[0] { - case "bash": - cmd.Root().GenBashCompletion(os.Stdout) - case "zsh": - cmd.Root().GenZshCompletion(os.Stdout) - case "fish": - cmd.Root().GenFishCompletion(os.Stdout, true) - case "powershell": - cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) - } - }, -} -``` - -**Note:** The cobra generator may include messages printed to stdout, for example, if the config file is loaded; this will break the auto-completion script so must be removed. - -## Adapting the default completion command - -Cobra provides a few options for the default `completion` command. To configure such options you must set -the `CompletionOptions` field on the *root* command. - -To tell Cobra *not* to provide the default `completion` command: -``` -rootCmd.CompletionOptions.DisableDefaultCmd = true -``` - -To tell Cobra to mark the default `completion` command as *hidden*: -``` -rootCmd.CompletionOptions.HiddenDefaultCmd = true -``` - -To tell Cobra *not* to provide the user with the `--no-descriptions` flag to the completion sub-commands: -``` -rootCmd.CompletionOptions.DisableNoDescFlag = true -``` - -To tell Cobra to completely disable descriptions for completions: -``` -rootCmd.CompletionOptions.DisableDescriptions = true -``` - -# Customizing completions - -The generated completion scripts will automatically handle completing commands and flags. However, you can make your completions much more powerful by providing information to complete your program's nouns and flag values. - -## Completion of nouns - -### Static completion of nouns - -Cobra allows you to provide a pre-defined list of completion choices for your nouns using the `ValidArgs` field. -For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns" you have to set them. -Some simplified code from `kubectl get` looks like: - -```go -validArgs = []string{ "pod", "node", "service", "replicationcontroller" } - -cmd := &cobra.Command{ - Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", - Short: "Display one or many resources", - Long: get_long, - Example: get_example, - Run: func(cmd *cobra.Command, args []string) { - cobra.CheckErr(RunGet(f, out, cmd, args)) - }, - ValidArgs: validArgs, -} -``` - -Notice we put the `ValidArgs` field on the `get` sub-command. Doing so will give results like: - -```bash -$ kubectl get [tab][tab] -node pod replicationcontroller service -``` - -#### Aliases for nouns - -If your nouns have aliases, you can define them alongside `ValidArgs` using `ArgAliases`: - -```go -argAliases = []string { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } - -cmd := &cobra.Command{ - ... - ValidArgs: validArgs, - ArgAliases: argAliases -} -``` - -The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by -the completion algorithm if entered manually, e.g. in: - -```bash -$ kubectl get rc [tab][tab] -backend frontend database -``` - -Note that without declaring `rc` as an alias, the completion algorithm would not know to show the list of -replication controllers following `rc`. - -### Dynamic completion of nouns - -In some cases it is not possible to provide a list of completions in advance. Instead, the list of completions must be determined at execution-time. In a similar fashion as for static completions, you can use the `ValidArgsFunction` field to provide a Go function that Cobra will execute when it needs the list of completion choices for the nouns of a command. Note that either `ValidArgs` or `ValidArgsFunction` can be used for a single cobra command, but not both. -Simplified code from `helm status` looks like: - -```go -cmd := &cobra.Command{ - Use: "status RELEASE_NAME", - Short: "Display the status of the named release", - Long: status_long, - RunE: func(cmd *cobra.Command, args []string) { - RunGet(args[0]) - }, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return getReleasesFromCluster(toComplete), cobra.ShellCompDirectiveNoFileComp - }, -} -``` -Where `getReleasesFromCluster()` is a Go function that obtains the list of current Helm releases running on the Kubernetes cluster. -Notice we put the `ValidArgsFunction` on the `status` sub-command. Let's assume the Helm releases on the cluster are: `harbor`, `notary`, `rook` and `thanos` then this dynamic completion will give results like: - -```bash -$ helm status [tab][tab] -harbor notary rook thanos -``` -You may have noticed the use of `cobra.ShellCompDirective`. These directives are bit fields allowing to control some shell completion behaviors for your particular completion. You can combine them with the bit-or operator such as `cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp` -```go -// Indicates that the shell will perform its default behavior after completions -// have been provided (this implies none of the other directives). -ShellCompDirectiveDefault - -// Indicates an error occurred and completions should be ignored. -ShellCompDirectiveError - -// Indicates that the shell should not add a space after the completion, -// even if there is a single completion provided. -ShellCompDirectiveNoSpace - -// Indicates that the shell should not provide file completion even when -// no completion is provided. -ShellCompDirectiveNoFileComp - -// Indicates that the returned completions should be used as file extension filters. -// For example, to complete only files of the form *.json or *.yaml: -// return []string{"yaml", "json"}, ShellCompDirectiveFilterFileExt -// For flags, using MarkFlagFilename() and MarkPersistentFlagFilename() -// is a shortcut to using this directive explicitly. -// -ShellCompDirectiveFilterFileExt - -// Indicates that only directory names should be provided in file completion. -// For example: -// return nil, ShellCompDirectiveFilterDirs -// For flags, using MarkFlagDirname() is a shortcut to using this directive explicitly. -// -// To request directory names within another directory, the returned completions -// should specify a single directory name within which to search. For example, -// to complete directories within "themes/": -// return []string{"themes"}, ShellCompDirectiveFilterDirs -// -ShellCompDirectiveFilterDirs -``` - -***Note***: When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function. - -#### Debugging - -Cobra achieves dynamic completion through the use of a hidden command called by the completion script. To debug your Go completion code, you can call this hidden command directly: -```bash -$ helm __complete status har -harbor -:4 -Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr -``` -***Important:*** If the noun to complete is empty (when the user has not yet typed any letters of that noun), you must pass an empty parameter to the `__complete` command: -```bash -$ helm __complete status "" -harbor -notary -rook -thanos -:4 -Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr -``` -Calling the `__complete` command directly allows you to run the Go debugger to troubleshoot your code. You can also add printouts to your code; Cobra provides the following functions to use for printouts in Go completion code: -```go -// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE -// is set to a file path) and optionally prints to stderr. -cobra.CompDebug(msg string, printToStdErr bool) { -cobra.CompDebugln(msg string, printToStdErr bool) - -// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE -// is set to a file path) and to stderr. -cobra.CompError(msg string) -cobra.CompErrorln(msg string) -``` -***Important:*** You should **not** leave traces that print directly to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned above. - -## Completions for flags - -### Mark flags as required - -Most of the time completions will only show sub-commands. But if a flag is required to make a sub-command work, you probably want it to show up when the user types [tab][tab]. You can mark a flag as 'Required' like so: - -```go -cmd.MarkFlagRequired("pod") -cmd.MarkFlagRequired("container") -``` - -and you'll get something like - -```bash -$ kubectl exec [tab][tab] --c --container= -p --pod= -``` - -### Specify dynamic flag completion - -As for nouns, Cobra provides a way of defining dynamic completion of flags. To provide a Go function that Cobra will execute when it needs the list of completion choices for a flag, you must register the function using the `command.RegisterFlagCompletionFunc()` function. - -```go -flagName := "output" -cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{"json", "table", "yaml"}, cobra.ShellCompDirectiveDefault -}) -``` -Notice that calling `RegisterFlagCompletionFunc()` is done through the `command` with which the flag is associated. In our example this dynamic completion will give results like so: - -```bash -$ helm status --output [tab][tab] -json table yaml -``` - -#### Debugging - -You can also easily debug your Go completion code for flags: -```bash -$ helm __complete status --output "" -json -table -yaml -:4 -Completion ended with directive: ShellCompDirectiveNoFileComp # This is on stderr -``` -***Important:*** You should **not** leave traces that print to stdout in your completion code as they will be interpreted as completion choices by the completion script. Instead, use the cobra-provided debugging traces functions mentioned further above. - -### Specify valid filename extensions for flags that take a filename - -To limit completions of flag values to file names with certain extensions you can either use the different `MarkFlagFilename()` functions or a combination of `RegisterFlagCompletionFunc()` and `ShellCompDirectiveFilterFileExt`, like so: -```go -flagName := "output" -cmd.MarkFlagFilename(flagName, "yaml", "json") -``` -or -```go -flagName := "output" -cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{"yaml", "json"}, ShellCompDirectiveFilterFileExt}) -``` - -### Limit flag completions to directory names - -To limit completions of flag values to directory names you can either use the `MarkFlagDirname()` functions or a combination of `RegisterFlagCompletionFunc()` and `ShellCompDirectiveFilterDirs`, like so: -```go -flagName := "output" -cmd.MarkFlagDirname(flagName) -``` -or -```go -flagName := "output" -cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return nil, cobra.ShellCompDirectiveFilterDirs -}) -``` -To limit completions of flag values to directory names *within another directory* you can use a combination of `RegisterFlagCompletionFunc()` and `ShellCompDirectiveFilterDirs` like so: -```go -flagName := "output" -cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{"themes"}, cobra.ShellCompDirectiveFilterDirs -}) -``` -### Descriptions for completions - -Cobra provides support for completion descriptions. Such descriptions are supported for each shell -(however, for bash, it is only available in the [completion V2 version](#bash-completion-v2)). -For commands and flags, Cobra will provide the descriptions automatically, based on usage information. -For example, using zsh: -``` -$ helm s[tab] -search -- search for a keyword in charts -show -- show information of a chart -status -- displays the status of the named release -``` -while using fish: -``` -$ helm s[tab] -search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) -``` - -Cobra allows you to add descriptions to your own completions. Simply add the description text after each completion, following a `\t` separator. This technique applies to completions returned by `ValidArgs`, `ValidArgsFunction` and `RegisterFlagCompletionFunc()`. For example: -```go -ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{"harbor\tAn image registry", "thanos\tLong-term metrics"}, cobra.ShellCompDirectiveNoFileComp -}} -``` -or -```go -ValidArgs: []string{"bash\tCompletions for bash", "zsh\tCompletions for zsh"} -``` -## Bash completions - -### Dependencies - -The bash completion script generated by Cobra requires the `bash_completion` package. You should update the help text of your completion command to show how to install the `bash_completion` package ([Kubectl docs](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion)) - -### Aliases - -You can also configure `bash` aliases for your program and they will also support completions. - -```bash -alias aliasname=origcommand -complete -o default -F __start_origcommand aliasname - -# and now when you run `aliasname` completion will make -# suggestions as it did for `origcommand`. - -$ aliasname -completion firstcommand secondcommand -``` -### Bash legacy dynamic completions - -For backward compatibility, Cobra still supports its bash legacy dynamic completion solution. -Please refer to [Bash Completions](bash_completions.md) for details. - -### Bash completion V2 - -Cobra provides two versions for bash completion. The original bash completion (which started it all!) can be used by calling -`GenBashCompletion()` or `GenBashCompletionFile()`. - -A new V2 bash completion version is also available. This version can be used by calling `GenBashCompletionV2()` or -`GenBashCompletionFileV2()`. The V2 version does **not** support the legacy dynamic completion -(see [Bash Completions](bash_completions.md)) but instead works only with the Go dynamic completion -solution described in this document. -Unless your program already uses the legacy dynamic completion solution, it is recommended that you use the bash -completion V2 solution which provides the following extra features: -- Supports completion descriptions (like the other shells) -- Small completion script of less than 300 lines (v1 generates scripts of thousands of lines; `kubectl` for example has a bash v1 completion script of over 13K lines) -- Streamlined user experience thanks to a completion behavior aligned with the other shells - -`Bash` completion V2 supports descriptions for completions. When calling `GenBashCompletionV2()` or `GenBashCompletionFileV2()` -you must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra -will provide the description automatically based on usage information. You can choose to make this option configurable by -your users. - -``` -# With descriptions -$ helm s[tab][tab] -search (search for a keyword in charts) status (display the status of the named release) -show (show information of a chart) - -# Without descriptions -$ helm s[tab][tab] -search show status -``` -**Note**: Cobra's default `completion` command uses bash completion V2. If for some reason you need to use bash completion V1, you will need to implement your own `completion` command. -## Zsh completions - -Cobra supports native zsh completion generated from the root `cobra.Command`. -The generated completion script should be put somewhere in your `$fpath` and be named -`_`. You will need to start a new shell for the completions to become available. - -Zsh supports descriptions for completions. Cobra will provide the description automatically, -based on usage information. Cobra provides a way to completely disable such descriptions by -using `GenZshCompletionNoDesc()` or `GenZshCompletionFileNoDesc()`. You can choose to make -this a configurable option to your users. -``` -# With descriptions -$ helm s[tab] -search -- search for a keyword in charts -show -- show information of a chart -status -- displays the status of the named release - -# Without descriptions -$ helm s[tab] -search show status -``` -*Note*: Because of backward-compatibility requirements, we were forced to have a different API to disable completion descriptions between `zsh` and `fish`. - -### Limitations - -* Custom completions implemented in Bash scripting (legacy) are not supported and will be ignored for `zsh` (including the use of the `BashCompCustom` flag annotation). - * You should instead use `ValidArgsFunction` and `RegisterFlagCompletionFunc()` which are portable to the different shells (`bash`, `zsh`, `fish`, `powershell`). -* The function `MarkFlagCustom()` is not supported and will be ignored for `zsh`. - * You should instead use `RegisterFlagCompletionFunc()`. - -### Zsh completions standardization - -Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backward-compatible, some small changes in behavior were introduced. -Please refer to [Zsh Completions](zsh_completions.md) for details. - -## fish completions - -Cobra supports native fish completions generated from the root `cobra.Command`. You can use the `command.GenFishCompletion()` or `command.GenFishCompletionFile()` functions. You must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users. -``` -# With descriptions -$ helm s[tab] -search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) - -# Without descriptions -$ helm s[tab] -search show status -``` -*Note*: Because of backward-compatibility requirements, we were forced to have a different API to disable completion descriptions between `zsh` and `fish`. - -### Limitations - -* Custom completions implemented in bash scripting (legacy) are not supported and will be ignored for `fish` (including the use of the `BashCompCustom` flag annotation). - * You should instead use `ValidArgsFunction` and `RegisterFlagCompletionFunc()` which are portable to the different shells (`bash`, `zsh`, `fish`, `powershell`). -* The function `MarkFlagCustom()` is not supported and will be ignored for `fish`. - * You should instead use `RegisterFlagCompletionFunc()`. -* The following flag completion annotations are not supported and will be ignored for `fish`: - * `BashCompFilenameExt` (filtering by file extension) - * `BashCompSubdirsInDir` (filtering by directory) -* The functions corresponding to the above annotations are consequently not supported and will be ignored for `fish`: - * `MarkFlagFilename()` and `MarkPersistentFlagFilename()` (filtering by file extension) - * `MarkFlagDirname()` and `MarkPersistentFlagDirname()` (filtering by directory) -* Similarly, the following completion directives are not supported and will be ignored for `fish`: - * `ShellCompDirectiveFilterFileExt` (filtering by file extension) - * `ShellCompDirectiveFilterDirs` (filtering by directory) - -## PowerShell completions - -Cobra supports native PowerShell completions generated from the root `cobra.Command`. You can use the `command.GenPowerShellCompletion()` or `command.GenPowerShellCompletionFile()` functions. To include descriptions use `command.GenPowerShellCompletionWithDesc()` and `command.GenPowerShellCompletionFileWithDesc()`. Cobra will provide the description automatically based on usage information. You can choose to make this option configurable by your users. - -The script is designed to support all three PowerShell completion modes: - -* TabCompleteNext (default windows style - on each key press the next option is displayed) -* Complete (works like bash) -* MenuComplete (works like zsh) - -You set the mode with `Set-PSReadLineKeyHandler -Key Tab -Function `. Descriptions are only displayed when using the `Complete` or `MenuComplete` mode. - -Users need PowerShell version 5.0 or above, which comes with Windows 10 and can be downloaded separately for Windows 7 or 8.1. They can then write the completions to a file and source this file from their PowerShell profile, which is referenced by the `$Profile` environment variable. See `Get-Help about_Profiles` for more info about PowerShell profiles. - -``` -# With descriptions and Mode 'Complete' -$ helm s[tab] -search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) - -# With descriptions and Mode 'MenuComplete' The description of the current selected value will be displayed below the suggestions. -$ helm s[tab] -search show status - -search for a keyword in charts - -# Without descriptions -$ helm s[tab] -search show status -``` -### Aliases - -You can also configure `powershell` aliases for your program and they will also support completions. - -``` -$ sal aliasname origcommand -$ Register-ArgumentCompleter -CommandName 'aliasname' -ScriptBlock $__origcommandCompleterBlock - -# and now when you run `aliasname` completion will make -# suggestions as it did for `origcommand`. - -$ aliasname -completion firstcommand secondcommand -``` -The name of the completer block variable is of the form `$__CompleterBlock` where every `-` and `:` in the program name have been replaced with `_`, to respect powershell naming syntax. - -### Limitations - -* Custom completions implemented in bash scripting (legacy) are not supported and will be ignored for `powershell` (including the use of the `BashCompCustom` flag annotation). - * You should instead use `ValidArgsFunction` and `RegisterFlagCompletionFunc()` which are portable to the different shells (`bash`, `zsh`, `fish`, `powershell`). -* The function `MarkFlagCustom()` is not supported and will be ignored for `powershell`. - * You should instead use `RegisterFlagCompletionFunc()`. -* The following flag completion annotations are not supported and will be ignored for `powershell`: - * `BashCompFilenameExt` (filtering by file extension) - * `BashCompSubdirsInDir` (filtering by directory) -* The functions corresponding to the above annotations are consequently not supported and will be ignored for `powershell`: - * `MarkFlagFilename()` and `MarkPersistentFlagFilename()` (filtering by file extension) - * `MarkFlagDirname()` and `MarkPersistentFlagDirname()` (filtering by directory) -* Similarly, the following completion directives are not supported and will be ignored for `powershell`: - * `ShellCompDirectiveFilterFileExt` (filtering by file extension) - * `ShellCompDirectiveFilterDirs` (filtering by directory) diff --git a/vendor/github.com/spf13/cobra/user_guide.md b/vendor/github.com/spf13/cobra/user_guide.md deleted file mode 100644 index e55367e85..000000000 --- a/vendor/github.com/spf13/cobra/user_guide.md +++ /dev/null @@ -1,695 +0,0 @@ -# User Guide - -While you are welcome to provide your own organization, typically a Cobra-based -application will follow the following organizational structure: - -``` - ▾ appName/ - ▾ cmd/ - add.go - your.go - commands.go - here.go - main.go -``` - -In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. - -```go -package main - -import ( - "{pathToYourApp}/cmd" -) - -func main() { - cmd.Execute() -} -``` - -## Using the Cobra Generator - -Cobra-CLI is its own program that will create your application and add any -commands you want. It's the easiest way to incorporate Cobra into your application. - -For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) - -## Using the Cobra Library - -To manually implement Cobra you need to create a bare main.go file and a rootCmd file. -You will optionally provide additional commands as you see fit. - -### Create rootCmd - -Cobra doesn't require any special constructors. Simply create your commands. - -Ideally you place this in app/cmd/root.go: - -```go -var rootCmd = &cobra.Command{ - Use: "hugo", - Short: "Hugo is a very fast static site generator", - Long: `A Fast and Flexible Static Site Generator built with - love by spf13 and friends in Go. - Complete documentation is available at https://gohugo.io/documentation/`, - Run: func(cmd *cobra.Command, args []string) { - // Do Stuff Here - }, -} - -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} -``` - -You will additionally define flags and handle configuration in your init() function. - -For example cmd/root.go: - -```go -package cmd - -import ( - "fmt" - "os" - - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var ( - // Used for flags. - cfgFile string - userLicense string - - rootCmd = &cobra.Command{ - Use: "cobra-cli", - Short: "A generator for Cobra based Applications", - Long: `Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - } -) - -// Execute executes the root command. -func Execute() error { - return rootCmd.Execute() -} - -func init() { - cobra.OnInitialize(initConfig) - - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") - rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") - rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") - rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") - viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) - viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) - viper.SetDefault("author", "NAME HERE ") - viper.SetDefault("license", "apache") - - rootCmd.AddCommand(addCmd) - rootCmd.AddCommand(initCmd) -} - -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := os.UserHomeDir() - cobra.CheckErr(err) - - // Search config in home directory with name ".cobra" (without extension). - viper.AddConfigPath(home) - viper.SetConfigType("yaml") - viper.SetConfigName(".cobra") - } - - viper.AutomaticEnv() - - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } -} -``` - -### Create your main.go - -With the root command you need to have your main function execute it. -Execute should be run on the root for clarity, though it can be called on any command. - -In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra. - -```go -package main - -import ( - "{pathToYourApp}/cmd" -) - -func main() { - cmd.Execute() -} -``` - -### Create additional commands - -Additional commands can be defined and typically are each given their own file -inside of the cmd/ directory. - -If you wanted to create a version command you would create cmd/version.go and -populate it with the following: - -```go -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(versionCmd) -} - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number of Hugo", - Long: `All software has versions. This is Hugo's`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") - }, -} -``` - -### Returning and handling errors - -If you wish to return an error to the caller of a command, `RunE` can be used. - -```go -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(tryCmd) -} - -var tryCmd = &cobra.Command{ - Use: "try", - Short: "Try and possibly fail at something", - RunE: func(cmd *cobra.Command, args []string) error { - if err := someFunc(); err != nil { - return err - } - return nil - }, -} -``` - -The error can then be caught at the execute function call. - -## Working with Flags - -Flags provide modifiers to control how the action command operates. - -### Assign flags to a command - -Since the flags are defined and used in different locations, we need to -define a variable outside with the correct scope to assign the flag to -work with. - -```go -var Verbose bool -var Source string -``` - -There are two different approaches to assign a flag. - -### Persistent Flags - -A flag can be 'persistent', meaning that this flag will be available to the -command it's assigned to as well as every command under that command. For -global flags, assign a flag as a persistent flag on the root. - -```go -rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") -``` - -### Local Flags - -A flag can also be assigned locally, which will only apply to that specific command. - -```go -localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") -``` - -### Local Flag on Parent Commands - -By default, Cobra only parses local flags on the target command, and any local flags on -parent commands are ignored. By enabling `Command.TraverseChildren`, Cobra will -parse local flags on each command before executing the target command. - -```go -command := cobra.Command{ - Use: "print [OPTIONS] [COMMANDS]", - TraverseChildren: true, -} -``` - -### Bind Flags with Config - -You can also bind your flags with [viper](https://github.com/spf13/viper): -```go -var author string - -func init() { - rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") - viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) -} -``` - -In this example, the persistent flag `author` is bound with `viper`. -**Note**: the variable `author` will not be set to the value from config, -when the `--author` flag is provided by user. - -More in [viper documentation](https://github.com/spf13/viper#working-with-flags). - -### Required flags - -Flags are optional by default. If instead you wish your command to report an error -when a flag has not been set, mark it as required: -```go -rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") -rootCmd.MarkFlagRequired("region") -``` - -Or, for persistent flags: -```go -rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)") -rootCmd.MarkPersistentFlagRequired("region") -``` - -### Flag Groups - -If you have different flags that must be provided together (e.g. if they provide the `--username` flag they MUST provide the `--password` flag as well) then -Cobra can enforce that requirement: -```go -rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)") -rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)") -rootCmd.MarkFlagsRequiredTogether("username", "password") -``` - -You can also prevent different flags from being provided together if they represent mutually -exclusive options such as specifying an output format as either `--json` or `--yaml` but never both: -```go -rootCmd.Flags().BoolVar(&u, "json", false, "Output in JSON") -rootCmd.Flags().BoolVar(&pw, "yaml", false, "Output in YAML") -rootCmd.MarkFlagsMutuallyExclusive("json", "yaml") -``` - -In both of these cases: - - both local and persistent flags can be used - - **NOTE:** the group is only enforced on commands where every flag is defined - - a flag may appear in multiple groups - - a group may contain any number of flags - -## Positional and Custom Arguments - -Validation of positional arguments can be specified using the `Args` field of `Command`. -The following validators are built in: - -- Number of arguments: - - `NoArgs` - report an error if there are any positional args. - - `ArbitraryArgs` - accept any number of args. - - `MinimumNArgs(int)` - report an error if less than N positional args are provided. - - `MaximumNArgs(int)` - report an error if more than N positional args are provided. - - `ExactArgs(int)` - report an error if there are not exactly N positional args. - - `RangeArgs(min, max)` - report an error if the number of args is not between `min` and `max`. -- Content of the arguments: - - `OnlyValidArgs` - report an error if there are any positional args not specified in the `ValidArgs` field of `Command`, which can optionally be set to a list of valid values for positional args. - -If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`. - -Moreover, `MatchAll(pargs ...PositionalArgs)` enables combining existing checks with arbitrary other checks. -For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional -args that are not in the `ValidArgs` field of `Command`, you can call `MatchAll` on `ExactArgs` and `OnlyValidArgs`, as -shown below: - -```go -var cmd = &cobra.Command{ - Short: "hello", - Args: MatchAll(ExactArgs(2), OnlyValidArgs), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hello, World!") - }, -} -``` - -It is possible to set any custom validator that satisfies `func(cmd *cobra.Command, args []string) error`. -For example: - -```go -var cmd = &cobra.Command{ - Short: "hello", - Args: func(cmd *cobra.Command, args []string) error { - // Optionally run one of the validators provided by cobra - if err := cobra.MinimumNArgs(1)(cmd, args); err != nil { - return err - } - // Run the custom validation logic - if myapp.IsValidColor(args[0]) { - return nil - } - return fmt.Errorf("invalid color specified: %s", args[0]) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hello, World!") - }, -} -``` - -## Example - -In the example below, we have defined three commands. Two are at the top level -and one (cmdTimes) is a child of one of the top commands. In this case the root -is not executable, meaning that a subcommand is required. This is accomplished -by not providing a 'Run' for the 'rootCmd'. - -We have only defined one flag for a single command. - -More documentation about flags is available at https://github.com/spf13/pflag - -```go -package main - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" -) - -func main() { - var echoTimes int - - var cmdPrint = &cobra.Command{ - Use: "print [string to print]", - Short: "Print anything to the screen", - Long: `print is for printing anything back to the screen. -For many years people have printed back to the screen.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Print: " + strings.Join(args, " ")) - }, - } - - var cmdEcho = &cobra.Command{ - Use: "echo [string to echo]", - Short: "Echo anything to the screen", - Long: `echo is for echoing anything back. -Echo works a lot like print, except it has a child command.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Echo: " + strings.Join(args, " ")) - }, - } - - var cmdTimes = &cobra.Command{ - Use: "times [string to echo]", - Short: "Echo anything to the screen more times", - Long: `echo things multiple times back to the user by providing -a count and a string.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - for i := 0; i < echoTimes; i++ { - fmt.Println("Echo: " + strings.Join(args, " ")) - } - }, - } - - cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") - - var rootCmd = &cobra.Command{Use: "app"} - rootCmd.AddCommand(cmdPrint, cmdEcho) - cmdEcho.AddCommand(cmdTimes) - rootCmd.Execute() -} -``` - -For a more complete example of a larger application, please checkout [Hugo](https://gohugo.io/). - -## Help Command - -Cobra automatically adds a help command to your application when you have subcommands. -This will be called when a user runs 'app help'. Additionally, help will also -support all other commands as input. Say, for instance, you have a command called -'create' without any additional configuration; Cobra will work when 'app help -create' is called. Every command will automatically have the '--help' flag added. - -### Example - -The following output is automatically generated by Cobra. Nothing beyond the -command and flag definitions are needed. - - $ cobra-cli help - - Cobra is a CLI library for Go that empowers applications. - This application is a tool to generate the needed files - to quickly create a Cobra application. - - Usage: - cobra-cli [command] - - Available Commands: - add Add a command to a Cobra Application - completion Generate the autocompletion script for the specified shell - help Help about any command - init Initialize a Cobra Application - - Flags: - -a, --author string author name for copyright attribution (default "YOUR NAME") - --config string config file (default is $HOME/.cobra.yaml) - -h, --help help for cobra-cli - -l, --license string name of license for the project - --viper use Viper for configuration - - Use "cobra-cli [command] --help" for more information about a command. - - -Help is just a command like any other. There is no special logic or behavior -around it. In fact, you can provide your own if you want. - -### Grouping commands in help - -Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly -defined using `AddGroup()` on the parent command. Then a subcommand can be added to a group using the `GroupID` element -of that subcommand. The groups will appear in the help output in the same order as they are defined using different -calls to `AddGroup()`. If you use the generated `help` or `completion` commands, you can set their group ids using -`SetHelpCommandGroupId()` and `SetCompletionCommandGroupId()` on the root command, respectively. - -### Defining your own help - -You can provide your own Help command or your own template for the default command to use -with the following functions: - -```go -cmd.SetHelpCommand(cmd *Command) -cmd.SetHelpFunc(f func(*Command, []string)) -cmd.SetHelpTemplate(s string) -``` - -The latter two will also apply to any children commands. - -## Usage Message - -When the user provides an invalid flag or invalid command, Cobra responds by -showing the user the 'usage'. - -### Example -You may recognize this from the help above. That's because the default help -embeds the usage as part of its output. - - $ cobra-cli --invalid - Error: unknown flag: --invalid - Usage: - cobra-cli [command] - - Available Commands: - add Add a command to a Cobra Application - completion Generate the autocompletion script for the specified shell - help Help about any command - init Initialize a Cobra Application - - Flags: - -a, --author string author name for copyright attribution (default "YOUR NAME") - --config string config file (default is $HOME/.cobra.yaml) - -h, --help help for cobra-cli - -l, --license string name of license for the project - --viper use Viper for configuration - - Use "cobra [command] --help" for more information about a command. - -### Defining your own usage -You can provide your own usage function or template for Cobra to use. -Like help, the function and template are overridable through public methods: - -```go -cmd.SetUsageFunc(f func(*Command) error) -cmd.SetUsageTemplate(s string) -``` - -## Version Flag - -Cobra adds a top-level '--version' flag if the Version field is set on the root command. -Running an application with the '--version' flag will print the version to stdout using -the version template. The template can be customized using the -`cmd.SetVersionTemplate(s string)` function. - -## PreRun and PostRun Hooks - -It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: - -- `PersistentPreRun` -- `PreRun` -- `Run` -- `PostRun` -- `PersistentPostRun` - -An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: - -```go -package main - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func main() { - - var rootCmd = &cobra.Command{ - Use: "root [sub]", - Short: "My root command", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) - }, - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) - }, - } - - var subCmd = &cobra.Command{ - Use: "sub [no options!]", - Short: "My subcommand", - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) - }, - } - - rootCmd.AddCommand(subCmd) - - rootCmd.SetArgs([]string{""}) - rootCmd.Execute() - fmt.Println() - rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) - rootCmd.Execute() -} -``` - -Output: -``` -Inside rootCmd PersistentPreRun with args: [] -Inside rootCmd PreRun with args: [] -Inside rootCmd Run with args: [] -Inside rootCmd PostRun with args: [] -Inside rootCmd PersistentPostRun with args: [] - -Inside rootCmd PersistentPreRun with args: [arg1 arg2] -Inside subCmd PreRun with args: [arg1 arg2] -Inside subCmd Run with args: [arg1 arg2] -Inside subCmd PostRun with args: [arg1 arg2] -Inside subCmd PersistentPostRun with args: [arg1 arg2] -``` - -## Suggestions when "unknown command" happens - -Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: - -``` -$ hugo srever -Error: unknown command "srever" for "hugo" - -Did you mean this? - server - -Run 'hugo --help' for usage. -``` - -Suggestions are automatically generated based on existing subcommands and use an implementation of [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. - -If you need to disable suggestions or tweak the string distance in your command, use: - -```go -command.DisableSuggestions = true -``` - -or - -```go -command.SuggestionsMinimumDistance = 1 -``` - -You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but make sense in your set of commands but for which -you don't want aliases. Example: - -``` -$ kubectl remove -Error: unknown command "remove" for "kubectl" - -Did you mean this? - delete - -Run 'kubectl help' for usage. -``` - -## Generating documentation for your command - -Cobra can generate documentation based on subcommands, flags, etc. Read more about it in the [docs generation documentation](doc/README.md). - -## Generating shell completions - -Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md). - -## Providing Active Help - -Cobra makes use of the shell-completion system to define a framework allowing you to provide Active Help to your users. Active Help are messages (hints, warnings, etc) printed as the program is being used. Read more about it in [Active Help](active_help.md). diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go index 84cec76fd..1856e4c7f 100644 --- a/vendor/github.com/spf13/cobra/zsh_completions.go +++ b/vendor/github.com/spf13/cobra/zsh_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -90,6 +90,7 @@ func genZshComp(buf io.StringWriter, name string, includeDesc bool) { compCmd = ShellCompNoDescRequestCmd } WriteStringAndCheck(buf, fmt.Sprintf(`#compdef %[1]s +compdef _%[1]s %[1]s # zsh completion for %-36[1]s -*- shell-script -*- @@ -108,8 +109,9 @@ _%[1]s() local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d + local shellCompDirectiveKeepOrder=%[8]d - local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace + local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder local -a completions __%[1]s_debug "\n========= starting completion logic ==========" @@ -177,7 +179,7 @@ _%[1]s() return fi - local activeHelpMarker="%[8]s" + local activeHelpMarker="%[9]s" local endIndex=${#activeHelpMarker} local startIndex=$((${#activeHelpMarker}+1)) local hasActiveHelp=0 @@ -227,6 +229,11 @@ _%[1]s() noSpace="-S ''" fi + if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then + __%[1]s_debug "Activating keep order." + keepOrder="-V" + fi + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local filteringCmd @@ -262,7 +269,7 @@ _%[1]s() return $result else __%[1]s_debug "Calling _describe" - if eval _describe "completions" completions $flagPrefix $noSpace; then + if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then __%[1]s_debug "_describe found some completions" # Return the success of having called _describe @@ -296,6 +303,6 @@ if [ "$funcstack[1]" = "_%[1]s" ]; then fi `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpMarker)) } diff --git a/vendor/github.com/spf13/cobra/zsh_completions.md b/vendor/github.com/spf13/cobra/zsh_completions.md deleted file mode 100644 index 7cff61787..000000000 --- a/vendor/github.com/spf13/cobra/zsh_completions.md +++ /dev/null @@ -1,48 +0,0 @@ -## Generating Zsh Completion For Your cobra.Command - -Please refer to [Shell Completions](shell_completions.md) for details. - -## Zsh completions standardization - -Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced. - -### Deprecation summary - -See further below for more details on these deprecations. - -* `cmd.MarkZshCompPositionalArgumentFile(pos, []string{})` is no longer needed. It is therefore **deprecated** and silently ignored. -* `cmd.MarkZshCompPositionalArgumentFile(pos, glob[])` is **deprecated** and silently ignored. - * Instead use `ValidArgsFunction` with `ShellCompDirectiveFilterFileExt`. -* `cmd.MarkZshCompPositionalArgumentWords()` is **deprecated** and silently ignored. - * Instead use `ValidArgsFunction`. - -### Behavioral changes - -**Noun completion** -|Old behavior|New behavior| -|---|---| -|No file completion by default (opposite of bash)|File completion by default; use `ValidArgsFunction` with `ShellCompDirectiveNoFileComp` to turn off file completion on a per-argument basis| -|Completion of flag names without the `-` prefix having been typed|Flag names are only completed if the user has typed the first `-`| -`cmd.MarkZshCompPositionalArgumentFile(pos, []string{})` used to turn on file completion on a per-argument position basis|File completion for all arguments by default; `cmd.MarkZshCompPositionalArgumentFile()` is **deprecated** and silently ignored| -|`cmd.MarkZshCompPositionalArgumentFile(pos, glob[])` used to turn on file completion **with glob filtering** on a per-argument position basis (zsh-specific)|`cmd.MarkZshCompPositionalArgumentFile()` is **deprecated** and silently ignored; use `ValidArgsFunction` with `ShellCompDirectiveFilterFileExt` for file **extension** filtering (not full glob filtering)| -|`cmd.MarkZshCompPositionalArgumentWords(pos, words[])` used to provide completion choices on a per-argument position basis (zsh-specific)|`cmd.MarkZshCompPositionalArgumentWords()` is **deprecated** and silently ignored; use `ValidArgsFunction` to achieve the same behavior| - -**Flag-value completion** - -|Old behavior|New behavior| -|---|---| -|No file completion by default (opposite of bash)|File completion by default; use `RegisterFlagCompletionFunc()` with `ShellCompDirectiveNoFileComp` to turn off file completion| -|`cmd.MarkFlagFilename(flag, []string{})` and similar used to turn on file completion|File completion by default; `cmd.MarkFlagFilename(flag, []string{})` no longer needed in this context and silently ignored| -|`cmd.MarkFlagFilename(flag, glob[])` used to turn on file completion **with glob filtering** (syntax of `[]string{"*.yaml", "*.yml"}` incompatible with bash)|Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells (`[]string{"yaml", "yml"}`)| -|`cmd.MarkFlagDirname(flag)` only completes directories (zsh-specific)|Has been added for all shells| -|Completion of a flag name does not repeat, unless flag is of type `*Array` or `*Slice` (not supported by bash)|Retained for `zsh` and added to `fish`| -|Completion of a flag name does not provide the `=` form (unlike bash)|Retained for `zsh` and added to `fish`| - -**Improvements** - -* Custom completion support (`ValidArgsFunction` and `RegisterFlagCompletionFunc()`) -* File completion by default if no other completions found -* Handling of required flags -* File extension filtering no longer mutually exclusive with bash usage -* Completion of directory names *within* another directory -* Support for `=` form of flags diff --git a/vendor/modules.txt b/vendor/modules.txt index 2fada1eb0..5d8815e92 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -361,7 +361,7 @@ github.com/hashicorp/hcl/json/token github.com/hexops/gotextdiff github.com/hexops/gotextdiff/myers github.com/hexops/gotextdiff/span -# github.com/inconshreveable/mousetrap v1.0.1 +# github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap # github.com/jgautheron/goconst v1.5.1 @@ -663,7 +663,7 @@ github.com/spf13/afero/mem # github.com/spf13/cast v1.5.0 ## explicit; go 1.18 github.com/spf13/cast -# github.com/spf13/cobra v1.6.1 +# github.com/spf13/cobra v1.8.0 ## explicit; go 1.15 github.com/spf13/cobra # github.com/spf13/jwalterweatherman v1.1.0 From 7695e46ed8ec3677021ba8fdcfda005f01729335 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:38:32 +0200 Subject: [PATCH 23/31] gomod: Update github.com/stretchr/testify --- go.mod | 4 +- go.sum | 7 +- vendor/github.com/stretchr/objx/README.md | 8 +- vendor/github.com/stretchr/objx/Taskfile.yml | 5 +- vendor/github.com/stretchr/objx/accessors.go | 24 +- .../github.com/stretchr/objx/conversions.go | 4 +- vendor/github.com/stretchr/objx/doc.go | 44 +- vendor/github.com/stretchr/objx/map.go | 9 +- .../testify/assert/assertion_compare.go | 64 ++- .../assert/assertion_compare_can_convert.go | 16 - .../assert/assertion_compare_legacy.go | 16 - .../testify/assert/assertion_format.go | 244 +++++---- .../testify/assert/assertion_forward.go | 483 ++++++++++------- .../testify/assert/assertion_order.go | 24 +- .../stretchr/testify/assert/assertions.go | 465 ++++++++++++---- .../github.com/stretchr/testify/assert/doc.go | 43 +- .../testify/assert/http_assertions.go | 39 +- .../github.com/stretchr/testify/mock/doc.go | 30 +- .../github.com/stretchr/testify/mock/mock.go | 253 +++++++-- .../stretchr/testify/require/doc.go | 23 +- .../stretchr/testify/require/require.go | 501 +++++++++++------- .../testify/require/require_forward.go | 483 ++++++++++------- .../github.com/stretchr/testify/suite/doc.go | 59 ++- .../stretchr/testify/suite/suite.go | 27 +- vendor/modules.txt | 8 +- 25 files changed, 1829 insertions(+), 1054 deletions(-) delete mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go delete mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go diff --git a/go.mod b/go.mod index 9424f4c56..6bfacc70b 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/sony/gobreaker v0.5.0 github.com/spf13/cobra v1.8.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.9.0 github.com/uber/jaeger-client-go v2.14.0+incompatible github.com/uber/jaeger-lib v1.5.0 github.com/zenazn/goji v0.9.0 @@ -189,7 +189,7 @@ require ( github.com/spf13/viper v1.12.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect github.com/tdakkota/asciicheck v0.1.1 // indirect diff --git a/go.sum b/go.sum index 574fb6e64..110bdeed3 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,9 @@ github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8L 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -637,8 +638,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= diff --git a/vendor/github.com/stretchr/objx/README.md b/vendor/github.com/stretchr/objx/README.md index 246660b21..78dc1f8b0 100644 --- a/vendor/github.com/stretchr/objx/README.md +++ b/vendor/github.com/stretchr/objx/README.md @@ -4,20 +4,20 @@ [![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage) [![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx) -[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx) +[![GoDoc](https://pkg.go.dev/badge/github.com/stretchr/objx?utm_source=godoc)](https://pkg.go.dev/github.com/stretchr/objx) Objx - Go package for dealing with maps, slices, JSON and other data. Get started: - Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date) -- Check out the API Documentation http://godoc.org/github.com/stretchr/objx +- Check out the API Documentation http://pkg.go.dev/github.com/stretchr/objx ## Overview Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. ### Pattern -Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: +Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: m, err := objx.FromJSON(json) @@ -74,7 +74,7 @@ To update Objx to the latest version, run: go get -u github.com/stretchr/objx ### Supported go versions -We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment. +We currently support the three recent major Go versions. ## Contributing Please feel free to submit issues, fork the repository and send pull requests! diff --git a/vendor/github.com/stretchr/objx/Taskfile.yml b/vendor/github.com/stretchr/objx/Taskfile.yml index 7746f516d..8a79e8d67 100644 --- a/vendor/github.com/stretchr/objx/Taskfile.yml +++ b/vendor/github.com/stretchr/objx/Taskfile.yml @@ -1,7 +1,4 @@ -version: '2' - -env: - GOFLAGS: -mod=vendor +version: '3' tasks: default: diff --git a/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/stretchr/objx/accessors.go index 4c6045588..72f1d1c1c 100644 --- a/vendor/github.com/stretchr/objx/accessors.go +++ b/vendor/github.com/stretchr/objx/accessors.go @@ -14,17 +14,17 @@ const ( // For example, `location.address.city` PathSeparator string = "." - // arrayAccesRegexString is the regex used to extract the array number + // arrayAccessRegexString is the regex used to extract the array number // from the access path - arrayAccesRegexString = `^(.+)\[([0-9]+)\]$` + arrayAccessRegexString = `^(.+)\[([0-9]+)\]$` // mapAccessRegexString is the regex used to extract the map key // from the access path mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$` ) -// arrayAccesRegex is the compiled arrayAccesRegexString -var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString) +// arrayAccessRegex is the compiled arrayAccessRegexString +var arrayAccessRegex = regexp.MustCompile(arrayAccessRegexString) // mapAccessRegex is the compiled mapAccessRegexString var mapAccessRegex = regexp.MustCompile(mapAccessRegexString) @@ -37,11 +37,11 @@ var mapAccessRegex = regexp.MustCompile(mapAccessRegexString) // // Get can only operate directly on map[string]interface{} and []interface. // -// Example +// # Example // // To access the title of the third chapter of the second book, do: // -// o.Get("books[1].chapters[2].title") +// o.Get("books[1].chapters[2].title") func (m Map) Get(selector string) *Value { rawObj := access(m, selector, nil, false) return &Value{data: rawObj} @@ -52,26 +52,26 @@ func (m Map) Get(selector string) *Value { // // Set can only operate directly on map[string]interface{} and []interface // -// Example +// # Example // // To set the title of the third chapter of the second book, do: // -// o.Set("books[1].chapters[2].title","Time to Go") +// o.Set("books[1].chapters[2].title","Time to Go") func (m Map) Set(selector string, value interface{}) Map { access(m, selector, value, true) return m } -// getIndex returns the index, which is hold in s by two braches. -// It also returns s withour the index part, e.g. name[1] will return (1, name). +// getIndex returns the index, which is hold in s by two branches. +// It also returns s without the index part, e.g. name[1] will return (1, name). // If no index is found, -1 is returned func getIndex(s string) (int, string) { - arrayMatches := arrayAccesRegex.FindStringSubmatch(s) + arrayMatches := arrayAccessRegex.FindStringSubmatch(s) if len(arrayMatches) > 0 { // Get the key into the map selector := arrayMatches[1] // Get the index into the array at the key - // We know this cannt fail because arrayMatches[2] is an int for sure + // We know this can't fail because arrayMatches[2] is an int for sure index, _ := strconv.Atoi(arrayMatches[2]) return index, selector } diff --git a/vendor/github.com/stretchr/objx/conversions.go b/vendor/github.com/stretchr/objx/conversions.go index 080aa46e4..01c63d7d3 100644 --- a/vendor/github.com/stretchr/objx/conversions.go +++ b/vendor/github.com/stretchr/objx/conversions.go @@ -15,7 +15,7 @@ import ( const SignatureSeparator = "_" // URLValuesSliceKeySuffix is the character that is used to -// specify a suffic for slices parsed by URLValues. +// specify a suffix for slices parsed by URLValues. // If the suffix is set to "[i]", then the index of the slice // is used in place of i // Ex: Suffix "[]" would have the form a[]=b&a[]=c @@ -30,7 +30,7 @@ const ( ) // SetURLValuesSliceKeySuffix sets the character that is used to -// specify a suffic for slices parsed by URLValues. +// specify a suffix for slices parsed by URLValues. // If the suffix is set to "[i]", then the index of the slice // is used in place of i // Ex: Suffix "[]" would have the form a[]=b&a[]=c diff --git a/vendor/github.com/stretchr/objx/doc.go b/vendor/github.com/stretchr/objx/doc.go index 6d6af1a83..b170af74b 100644 --- a/vendor/github.com/stretchr/objx/doc.go +++ b/vendor/github.com/stretchr/objx/doc.go @@ -1,19 +1,19 @@ /* -Objx - Go package for dealing with maps, slices, JSON and other data. +Package objx provides utilities for dealing with maps, slices, JSON and other data. -Overview +# Overview Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. -Pattern +# Pattern -Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. +Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: - m, err := objx.FromJSON(json) + m, err := objx.FromJSON(json) NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking. @@ -21,46 +21,46 @@ the rest will be optimistic and try to figure things out without panicking. Use `Get` to access the value you're interested in. You can use dot and array notation too: - m.Get("places[0].latlng") + m.Get("places[0].latlng") Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. - if m.Get("code").IsStr() { // Your code... } + if m.Get("code").IsStr() { // Your code... } Or you can just assume the type, and use one of the strong type methods to extract the real value: - m.Get("code").Int() + m.Get("code").Int() If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value. - Get("code").Int(-1) + Get("code").Int(-1) If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below. -Reading data +# Reading data A simple example of how to use Objx: - // Use MustFromJSON to make an objx.Map from some JSON - m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) + // Use MustFromJSON to make an objx.Map from some JSON + m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) - // Get the details - name := m.Get("name").Str() - age := m.Get("age").Int() + // Get the details + name := m.Get("name").Str() + age := m.Get("age").Int() - // Get their nickname (or use their name if they don't have one) - nickname := m.Get("nickname").Str(name) + // Get their nickname (or use their name if they don't have one) + nickname := m.Get("nickname").Str(name) -Ranging +# Ranging Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect: - m := objx.MustFromJSON(json) - for key, value := range m { - // Your code... - } + m := objx.MustFromJSON(json) + for key, value := range m { + // Your code... + } */ package objx diff --git a/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/stretchr/objx/map.go index a64712a08..ab9f9ae67 100644 --- a/vendor/github.com/stretchr/objx/map.go +++ b/vendor/github.com/stretchr/objx/map.go @@ -47,17 +47,16 @@ func New(data interface{}) Map { // // The arguments follow a key, value pattern. // -// // Returns nil if any key argument is non-string or if there are an odd number of arguments. // -// Example +// # Example // // To easily create Maps: // -// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) +// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) // -// // creates an Map equivalent to -// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} +// // creates an Map equivalent to +// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} func MSI(keyAndValuePairs ...interface{}) Map { newMap := Map{} keyAndValuePairsLen := len(keyAndValuePairs) diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go index 95d8e59da..4d4b4aad6 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -28,6 +28,8 @@ var ( uint32Type = reflect.TypeOf(uint32(1)) uint64Type = reflect.TypeOf(uint64(1)) + uintptrType = reflect.TypeOf(uintptr(1)) + float32Type = reflect.TypeOf(float32(1)) float64Type = reflect.TypeOf(float64(1)) @@ -308,11 +310,11 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { case reflect.Struct: { // All structs enter here. We're not interested in most types. - if !canConvert(obj1Value, timeType) { + if !obj1Value.CanConvert(timeType) { break } - // time.Time can compared! + // time.Time can be compared! timeObj1, ok := obj1.(time.Time) if !ok { timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) @@ -328,7 +330,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { case reflect.Slice: { // We only care about the []byte type. - if !canConvert(obj1Value, bytesType) { + if !obj1Value.CanConvert(bytesType) { break } @@ -345,6 +347,26 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true } + case reflect.Uintptr: + { + uintptrObj1, ok := obj1.(uintptr) + if !ok { + uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr) + } + uintptrObj2, ok := obj2.(uintptr) + if !ok { + uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr) + } + if uintptrObj1 > uintptrObj2 { + return compareGreater, true + } + if uintptrObj1 == uintptrObj2 { + return compareEqual, true + } + if uintptrObj1 < uintptrObj2 { + return compareLess, true + } + } } return compareEqual, false @@ -352,9 +374,9 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { // Greater asserts that the first element is greater than the second // -// assert.Greater(t, 2, 1) -// assert.Greater(t, float64(2), float64(1)) -// assert.Greater(t, "b", "a") +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -364,10 +386,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqual(t, 2, 1) -// assert.GreaterOrEqual(t, 2, 2) -// assert.GreaterOrEqual(t, "b", "a") -// assert.GreaterOrEqual(t, "b", "b") +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -377,9 +399,9 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in // Less asserts that the first element is less than the second // -// assert.Less(t, 1, 2) -// assert.Less(t, float64(1), float64(2)) -// assert.Less(t, "a", "b") +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -389,10 +411,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) // LessOrEqual asserts that the first element is less than or equal to the second // -// assert.LessOrEqual(t, 1, 2) -// assert.LessOrEqual(t, 2, 2) -// assert.LessOrEqual(t, "a", "b") -// assert.LessOrEqual(t, "b", "b") +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -402,8 +424,8 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter // Positive asserts that the specified element is positive // -// assert.Positive(t, 1) -// assert.Positive(t, 1.23) +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -414,8 +436,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { // Negative asserts that the specified element is negative // -// assert.Negative(t, -1) -// assert.Negative(t, -1.23) +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go deleted file mode 100644 index da867903e..000000000 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build go1.17 -// +build go1.17 - -// TODO: once support for Go 1.16 is dropped, this file can be -// merged/removed with assertion_compare_go1.17_test.go and -// assertion_compare_legacy.go - -package assert - -import "reflect" - -// Wrapper around reflect.Value.CanConvert, for compatibility -// reasons. -func canConvert(value reflect.Value, to reflect.Type) bool { - return value.CanConvert(to) -} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go deleted file mode 100644 index 1701af2a3..000000000 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build !go1.17 -// +build !go1.17 - -// TODO: once support for Go 1.16 is dropped, this file can be -// merged/removed with assertion_compare_go1.17_test.go and -// assertion_compare_can_convert.go - -package assert - -import "reflect" - -// Older versions of Go does not have the reflect.Value.CanConvert -// method. -func canConvert(value reflect.Value, to reflect.Type) bool { - return false -} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index 7880b8f94..3ddab109a 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -1,7 +1,4 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND - */ +// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package assert @@ -22,9 +19,9 @@ func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bo // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") -// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") -// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -56,7 +53,7 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Emptyf(t, obj, "error message %s", "formatted") +// assert.Emptyf(t, obj, "error message %s", "formatted") func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -66,7 +63,7 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) boo // Equalf asserts that two objects are equal. // -// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// assert.Equalf(t, 123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -81,8 +78,8 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -90,10 +87,27 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) } -// EqualValuesf asserts that two objects are equal or convertable to the same types +// EqualExportedValuesf asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true +// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false +func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// EqualValuesf asserts that two objects are equal or convertible to the same types // and equal. // -// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -103,10 +117,10 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Errorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -126,8 +140,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -147,7 +161,7 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -155,9 +169,34 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) } +// EventuallyWithTf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + // Exactlyf asserts that two objects are equal in value and type. // -// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -183,7 +222,7 @@ func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{} // Falsef asserts that the specified value is false. // -// assert.Falsef(t, myBool, "error message %s", "formatted") +// assert.Falsef(t, myBool, "error message %s", "formatted") func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -202,9 +241,9 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool // Greaterf asserts that the first element is greater than the second // -// assert.Greaterf(t, 2, 1, "error message %s", "formatted") -// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") -// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -214,10 +253,10 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -228,7 +267,7 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -241,7 +280,7 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -253,7 +292,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // HTTPErrorf asserts that a specified handler returns an error status code. // -// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -265,7 +304,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -277,7 +316,7 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { @@ -289,7 +328,7 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // -// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -301,7 +340,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin // Implementsf asserts that an object is implemented by the specified interface. // -// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -311,7 +350,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms // InDeltaf asserts that the two numerals are within delta of each other. // -// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -353,9 +392,9 @@ func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsil // IsDecreasingf asserts that the collection is decreasing // -// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -365,9 +404,9 @@ func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface // IsIncreasingf asserts that the collection is increasing // -// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -377,9 +416,9 @@ func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface // IsNonDecreasingf asserts that the collection is not decreasing // -// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -389,9 +428,9 @@ func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interf // IsNonIncreasingf asserts that the collection is not increasing // -// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -409,7 +448,7 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin // JSONEqf asserts that two JSON strings are equivalent. // -// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -420,7 +459,7 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -430,9 +469,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf // Lessf asserts that the first element is less than the second // -// assert.Lessf(t, 1, 2, "error message %s", "formatted") -// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") -// assert.Lessf(t, "a", "b", "error message %s", "formatted") +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -442,10 +481,10 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter // LessOrEqualf asserts that the first element is less than or equal to the second // -// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") -// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -455,8 +494,8 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . // Negativef asserts that the specified element is negative // -// assert.Negativef(t, -1, "error message %s", "formatted") -// assert.Negativef(t, -1.23, "error message %s", "formatted") +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -467,7 +506,7 @@ func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -477,7 +516,7 @@ func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time. // Nilf asserts that the specified object is nil. // -// assert.Nilf(t, err, "error message %s", "formatted") +// assert.Nilf(t, err, "error message %s", "formatted") func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -496,10 +535,10 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoErrorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -519,9 +558,9 @@ func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) boo // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -532,9 +571,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -544,7 +583,7 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) // NotEqualf asserts that the specified values are NOT equal. // -// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -557,7 +596,7 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -574,9 +613,19 @@ func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interf return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) } +// NotImplementsf asserts that an object does not implement the specified interface. +// +// assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotImplements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) +} + // NotNilf asserts that the specified object is not nil. // -// assert.NotNilf(t, err, "error message %s", "formatted") +// assert.NotNilf(t, err, "error message %s", "formatted") func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -586,7 +635,7 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bo // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -596,8 +645,8 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo // NotRegexpf asserts that a specified regexp does not match a string. // -// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -607,7 +656,7 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args .. // NotSamef asserts that two pointers do not reference the same object. // -// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -618,10 +667,12 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...) } -// NotSubsetf asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubsetf asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted") +// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -639,7 +690,7 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -651,7 +702,7 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -662,7 +713,7 @@ func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -672,8 +723,8 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str // Positivef asserts that the specified element is positive // -// assert.Positivef(t, 1, "error message %s", "formatted") -// assert.Positivef(t, 1.23, "error message %s", "formatted") +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -683,8 +734,8 @@ func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool // Regexpf asserts that a specified regexp matches a string. // -// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -694,7 +745,7 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in // Samef asserts that two pointers reference the same object. // -// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -705,10 +756,11 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg return Same(t, expected, actual, append([]interface{}{msg}, args...)...) } -// Subsetf asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subsetf asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted") +// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -718,7 +770,7 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args // Truef asserts that the specified value is true. // -// assert.Truef(t, myBool, "error message %s", "formatted") +// assert.Truef(t, myBool, "error message %s", "formatted") func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -728,7 +780,7 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { // WithinDurationf asserts that the two times are within duration delta of each other. // -// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -738,7 +790,7 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim // WithinRangef asserts that a time is within a time range (inclusive). // -// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 339515b8b..a84e09bd4 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -1,7 +1,4 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND - */ +// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package assert @@ -30,9 +27,9 @@ func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{} // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Contains("Hello World", "World") -// a.Contains(["Hello", "World"], "World") -// a.Contains({"Hello": "World"}, "Hello") +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -43,9 +40,9 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs .. // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Containsf("Hello World", "World", "error message %s", "formatted") -// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") -// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -98,7 +95,7 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Empty(obj) +// a.Empty(obj) func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -109,7 +106,7 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Emptyf(obj, "error message %s", "formatted") +// a.Emptyf(obj, "error message %s", "formatted") func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -119,7 +116,7 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) // Equal asserts that two objects are equal. // -// a.Equal(123, 123) +// a.Equal(123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -134,8 +131,8 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualError(err, expectedErrorString) +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -146,8 +143,8 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -155,10 +152,44 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a return EqualErrorf(a.t, theError, errString, msg, args...) } -// EqualValues asserts that two objects are equal or convertable to the same types +// EqualExportedValues asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true +// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false +func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualExportedValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualExportedValuesf asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true +// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false +func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualExportedValuesf(a.t, expected, actual, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertible to the same types // and equal. // -// a.EqualValues(uint32(123), int32(123)) +// a.EqualValues(uint32(123), int32(123)) func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -166,10 +197,10 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn return EqualValues(a.t, expected, actual, msgAndArgs...) } -// EqualValuesf asserts that two objects are equal or convertable to the same types +// EqualValuesf asserts that two objects are equal or convertible to the same types // and equal. // -// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -179,7 +210,7 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg // Equalf asserts that two objects are equal. // -// a.Equalf(123, 123, "error message %s", "formatted") +// a.Equalf(123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -193,10 +224,10 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Error(err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -225,8 +256,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContains(err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -237,8 +268,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -266,10 +297,10 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Errorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -280,7 +311,7 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -288,10 +319,60 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti return Eventually(a.t, condition, waitFor, tick, msgAndArgs...) } +// EventuallyWithT asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// a.EventuallyWithT(func(c *assert.CollectT) { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// EventuallyWithTf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) +} + // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -301,7 +382,7 @@ func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, t // Exactly asserts that two objects are equal in value and type. // -// a.Exactly(int32(123), int64(123)) +// a.Exactly(int32(123), int64(123)) func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -311,7 +392,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg // Exactlyf asserts that two objects are equal in value and type. // -// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -353,7 +434,7 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{ // False asserts that the specified value is false. // -// a.False(myBool) +// a.False(myBool) func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -363,7 +444,7 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { // Falsef asserts that the specified value is false. // -// a.Falsef(myBool, "error message %s", "formatted") +// a.Falsef(myBool, "error message %s", "formatted") func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -391,9 +472,9 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) b // Greater asserts that the first element is greater than the second // -// a.Greater(2, 1) -// a.Greater(float64(2), float64(1)) -// a.Greater("b", "a") +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -403,10 +484,10 @@ func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...inter // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqual(2, 1) -// a.GreaterOrEqual(2, 2) -// a.GreaterOrEqual("b", "a") -// a.GreaterOrEqual("b", "b") +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -416,10 +497,10 @@ func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs . // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") -// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") -// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") -// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -429,9 +510,9 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, // Greaterf asserts that the first element is greater than the second // -// a.Greaterf(2, 1, "error message %s", "formatted") -// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") -// a.Greaterf("b", "a", "error message %s", "formatted") +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -442,7 +523,7 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args . // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -455,7 +536,7 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -468,7 +549,7 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -481,7 +562,7 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { @@ -493,7 +574,7 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin // HTTPError asserts that a specified handler returns an error status code. // -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -505,7 +586,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // HTTPErrorf asserts that a specified handler returns an error status code. // -// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -517,7 +598,7 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -529,7 +610,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -541,7 +622,7 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { @@ -553,7 +634,7 @@ func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { @@ -565,7 +646,7 @@ func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, ur // HTTPSuccess asserts that a specified handler returns a success status code. // -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -577,7 +658,7 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // -// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { @@ -589,7 +670,7 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s // Implements asserts that an object is implemented by the specified interface. // -// a.Implements((*MyInterface)(nil), new(MyObject)) +// a.Implements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -599,7 +680,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, // Implementsf asserts that an object is implemented by the specified interface. // -// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -609,7 +690,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{} // InDelta asserts that the two numerals are within delta of each other. // -// a.InDelta(math.Pi, 22/7.0, 0.01) +// a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -651,7 +732,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del // InDeltaf asserts that the two numerals are within delta of each other. // -// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -693,9 +774,9 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo // IsDecreasing asserts that the collection is decreasing // -// a.IsDecreasing([]int{2, 1, 0}) -// a.IsDecreasing([]float{2, 1}) -// a.IsDecreasing([]string{"b", "a"}) +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -705,9 +786,9 @@ func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) // IsDecreasingf asserts that the collection is decreasing // -// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") -// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -717,9 +798,9 @@ func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...inter // IsIncreasing asserts that the collection is increasing // -// a.IsIncreasing([]int{1, 2, 3}) -// a.IsIncreasing([]float{1, 2}) -// a.IsIncreasing([]string{"a", "b"}) +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -729,9 +810,9 @@ func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) // IsIncreasingf asserts that the collection is increasing // -// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") -// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -741,9 +822,9 @@ func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...inter // IsNonDecreasing asserts that the collection is not decreasing // -// a.IsNonDecreasing([]int{1, 1, 2}) -// a.IsNonDecreasing([]float{1, 2}) -// a.IsNonDecreasing([]string{"a", "b"}) +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -753,9 +834,9 @@ func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface // IsNonDecreasingf asserts that the collection is not decreasing // -// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -765,9 +846,9 @@ func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...in // IsNonIncreasing asserts that the collection is not increasing // -// a.IsNonIncreasing([]int{2, 1, 1}) -// a.IsNonIncreasing([]float{2, 1}) -// a.IsNonIncreasing([]string{"b", "a"}) +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -777,9 +858,9 @@ func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface // IsNonIncreasingf asserts that the collection is not increasing // -// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -805,7 +886,7 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s // JSONEq asserts that two JSON strings are equivalent. // -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -815,7 +896,7 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf // JSONEqf asserts that two JSON strings are equivalent. // -// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -826,7 +907,7 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// a.Len(mySlice, 3) +// a.Len(mySlice, 3) func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -837,7 +918,7 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// a.Lenf(mySlice, 3, "error message %s", "formatted") +// a.Lenf(mySlice, 3, "error message %s", "formatted") func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -847,9 +928,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in // Less asserts that the first element is less than the second // -// a.Less(1, 2) -// a.Less(float64(1), float64(2)) -// a.Less("a", "b") +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -859,10 +940,10 @@ func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interfac // LessOrEqual asserts that the first element is less than or equal to the second // -// a.LessOrEqual(1, 2) -// a.LessOrEqual(2, 2) -// a.LessOrEqual("a", "b") -// a.LessOrEqual("b", "b") +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -872,10 +953,10 @@ func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...i // LessOrEqualf asserts that the first element is less than or equal to the second // -// a.LessOrEqualf(1, 2, "error message %s", "formatted") -// a.LessOrEqualf(2, 2, "error message %s", "formatted") -// a.LessOrEqualf("a", "b", "error message %s", "formatted") -// a.LessOrEqualf("b", "b", "error message %s", "formatted") +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -885,9 +966,9 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar // Lessf asserts that the first element is less than the second // -// a.Lessf(1, 2, "error message %s", "formatted") -// a.Lessf(float64(1), float64(2), "error message %s", "formatted") -// a.Lessf("a", "b", "error message %s", "formatted") +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -897,8 +978,8 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i // Negative asserts that the specified element is negative // -// a.Negative(-1) -// a.Negative(-1.23) +// a.Negative(-1) +// a.Negative(-1.23) func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -908,8 +989,8 @@ func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { // Negativef asserts that the specified element is negative // -// a.Negativef(-1, "error message %s", "formatted") -// a.Negativef(-1.23, "error message %s", "formatted") +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -920,7 +1001,7 @@ func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) b // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -931,7 +1012,7 @@ func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick ti // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -941,7 +1022,7 @@ func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick t // Nil asserts that the specified object is nil. // -// a.Nil(err) +// a.Nil(err) func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -951,7 +1032,7 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { // Nilf asserts that the specified object is nil. // -// a.Nilf(err, "error message %s", "formatted") +// a.Nilf(err, "error message %s", "formatted") func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -979,10 +1060,10 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -992,10 +1073,10 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1024,9 +1105,9 @@ func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContains("Hello World", "Earth") -// a.NotContains(["Hello", "World"], "Earth") -// a.NotContains({"Hello": "World"}, "Earth") +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1037,9 +1118,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") -// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") -// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1050,9 +1131,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1063,9 +1144,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) boo // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1075,7 +1156,7 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface // NotEqual asserts that the specified values are NOT equal. // -// a.NotEqual(obj1, obj2) +// a.NotEqual(obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1088,7 +1169,7 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValues(obj1, obj2) +// a.NotEqualValues(obj1, obj2) func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1098,7 +1179,7 @@ func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, ms // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1108,7 +1189,7 @@ func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, m // NotEqualf asserts that the specified values are NOT equal. // -// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1137,9 +1218,29 @@ func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...in return NotErrorIsf(a.t, err, target, msg, args...) } +// NotImplements asserts that an object does not implement the specified interface. +// +// a.NotImplements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotImplements(a.t, interfaceObject, object, msgAndArgs...) +} + +// NotImplementsf asserts that an object does not implement the specified interface. +// +// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotImplementsf(a.t, interfaceObject, object, msg, args...) +} + // NotNil asserts that the specified object is not nil. // -// a.NotNil(err) +// a.NotNil(err) func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1149,7 +1250,7 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool // NotNilf asserts that the specified object is not nil. // -// a.NotNilf(err, "error message %s", "formatted") +// a.NotNilf(err, "error message %s", "formatted") func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1159,7 +1260,7 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{} // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanics(func(){ RemainCalm() }) +// a.NotPanics(func(){ RemainCalm() }) func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1169,7 +1270,7 @@ func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1179,8 +1280,8 @@ func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{} // NotRegexp asserts that a specified regexp does not match a string. // -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1190,8 +1291,8 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in // NotRegexpf asserts that a specified regexp does not match a string. // -// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1201,7 +1302,7 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg // NotSame asserts that two pointers do not reference the same object. // -// a.NotSame(ptr1, ptr2) +// a.NotSame(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1214,7 +1315,7 @@ func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArg // NotSamef asserts that two pointers do not reference the same object. // -// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1225,10 +1326,12 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri return NotSamef(a.t, expected, actual, msg, args...) } -// NotSubset asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubset asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +// a.NotSubset([1, 3, 4], [1, 2]) +// a.NotSubset({"x": 1, "y": 2}, {"z": 3}) func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1236,10 +1339,12 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs return NotSubset(a.t, list, subset, msgAndArgs...) } -// NotSubsetf asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubsetf asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") +// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1265,7 +1370,7 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bo // Panics asserts that the code inside the specified PanicTestFunc panics. // -// a.Panics(func(){ GoCrazy() }) +// a.Panics(func(){ GoCrazy() }) func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1277,7 +1382,7 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1289,7 +1394,7 @@ func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndAr // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1300,7 +1405,7 @@ func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg str // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1311,7 +1416,7 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgA // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1321,7 +1426,7 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1331,8 +1436,8 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b // Positive asserts that the specified element is positive // -// a.Positive(1) -// a.Positive(1.23) +// a.Positive(1) +// a.Positive(1.23) func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1342,8 +1447,8 @@ func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { // Positivef asserts that the specified element is positive // -// a.Positivef(1, "error message %s", "formatted") -// a.Positivef(1.23, "error message %s", "formatted") +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1353,8 +1458,8 @@ func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) b // Regexp asserts that a specified regexp matches a string. // -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1364,8 +1469,8 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter // Regexpf asserts that a specified regexp matches a string. // -// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1375,7 +1480,7 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args . // Same asserts that two pointers reference the same object. // -// a.Same(ptr1, ptr2) +// a.Same(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1388,7 +1493,7 @@ func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs . // Samef asserts that two pointers reference the same object. // -// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// a.Samef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1399,10 +1504,11 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, return Samef(a.t, expected, actual, msg, args...) } -// Subset asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subset asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +// a.Subset([1, 2, 3], [1, 2]) +// a.Subset({"x": 1, "y": 2}, {"x": 1}) func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1410,10 +1516,11 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ... return Subset(a.t, list, subset, msgAndArgs...) } -// Subsetf asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subsetf asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") +// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1423,7 +1530,7 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a // True asserts that the specified value is true. // -// a.True(myBool) +// a.True(myBool) func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1433,7 +1540,7 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { // Truef asserts that the specified value is true. // -// a.Truef(myBool, "error message %s", "formatted") +// a.Truef(myBool, "error message %s", "formatted") func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1443,7 +1550,7 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { // WithinDuration asserts that the two times are within duration delta of each other. // -// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1453,7 +1560,7 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta // WithinDurationf asserts that the two times are within duration delta of each other. // -// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1463,7 +1570,7 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta // WithinRange asserts that a time is within a time range (inclusive). // -// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1473,7 +1580,7 @@ func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Tim // WithinRangef asserts that a time is within a time range (inclusive). // -// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go index 759448783..00df62a05 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -46,36 +46,36 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT // IsIncreasing asserts that the collection is increasing // -// assert.IsIncreasing(t, []int{1, 2, 3}) -// assert.IsIncreasing(t, []float{1, 2}) -// assert.IsIncreasing(t, []string{"a", "b"}) +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // IsNonIncreasing asserts that the collection is not increasing // -// assert.IsNonIncreasing(t, []int{2, 1, 1}) -// assert.IsNonIncreasing(t, []float{2, 1}) -// assert.IsNonIncreasing(t, []string{"b", "a"}) +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // IsDecreasing asserts that the collection is decreasing // -// assert.IsDecreasing(t, []int{2, 1, 0}) -// assert.IsDecreasing(t, []float{2, 1}) -// assert.IsDecreasing(t, []string{"b", "a"}) +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // IsNonDecreasing asserts that the collection is not decreasing // -// assert.IsNonDecreasing(t, []int{1, 1, 2}) -// assert.IsNonDecreasing(t, []float{1, 2}) -// assert.IsNonDecreasing(t, []string{"a", "b"}) +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index 2924cf3a1..0b7570f21 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -19,7 +19,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/pmezard/go-difflib/difflib" - yaml "gopkg.in/yaml.v3" + "gopkg.in/yaml.v3" ) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" @@ -75,6 +75,84 @@ func ObjectsAreEqual(expected, actual interface{}) bool { return bytes.Equal(exp, act) } +// copyExportedFields iterates downward through nested data structures and creates a copy +// that only contains the exported struct fields. +func copyExportedFields(expected interface{}) interface{} { + if isNil(expected) { + return expected + } + + expectedType := reflect.TypeOf(expected) + expectedKind := expectedType.Kind() + expectedValue := reflect.ValueOf(expected) + + switch expectedKind { + case reflect.Struct: + result := reflect.New(expectedType).Elem() + for i := 0; i < expectedType.NumField(); i++ { + field := expectedType.Field(i) + isExported := field.IsExported() + if isExported { + fieldValue := expectedValue.Field(i) + if isNil(fieldValue) || isNil(fieldValue.Interface()) { + continue + } + newValue := copyExportedFields(fieldValue.Interface()) + result.Field(i).Set(reflect.ValueOf(newValue)) + } + } + return result.Interface() + + case reflect.Ptr: + result := reflect.New(expectedType.Elem()) + unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface()) + result.Elem().Set(reflect.ValueOf(unexportedRemoved)) + return result.Interface() + + case reflect.Array, reflect.Slice: + var result reflect.Value + if expectedKind == reflect.Array { + result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem() + } else { + result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len()) + } + for i := 0; i < expectedValue.Len(); i++ { + index := expectedValue.Index(i) + if isNil(index) { + continue + } + unexportedRemoved := copyExportedFields(index.Interface()) + result.Index(i).Set(reflect.ValueOf(unexportedRemoved)) + } + return result.Interface() + + case reflect.Map: + result := reflect.MakeMap(expectedType) + for _, k := range expectedValue.MapKeys() { + index := expectedValue.MapIndex(k) + unexportedRemoved := copyExportedFields(index.Interface()) + result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved)) + } + return result.Interface() + + default: + return expected + } +} + +// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are +// considered equal. This comparison of only exported fields is applied recursively to nested data +// structures. +// +// This function does no assertion of any kind. +// +// Deprecated: Use [EqualExportedValues] instead. +func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool { + expectedCleaned := copyExportedFields(expected) + actualCleaned := copyExportedFields(actual) + return ObjectsAreEqualValues(expectedCleaned, actualCleaned) +} + // ObjectsAreEqualValues gets whether two objects are equal, or if their // values are equal. func ObjectsAreEqualValues(expected, actual interface{}) bool { @@ -82,17 +160,40 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { return true } - actualType := reflect.TypeOf(actual) - if actualType == nil { + expectedValue := reflect.ValueOf(expected) + actualValue := reflect.ValueOf(actual) + if !expectedValue.IsValid() || !actualValue.IsValid() { return false } - expectedValue := reflect.ValueOf(expected) - if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + + expectedType := expectedValue.Type() + actualType := actualValue.Type() + if !expectedType.ConvertibleTo(actualType) { + return false + } + + if !isNumericType(expectedType) || !isNumericType(actualType) { // Attempt comparison after type conversion - return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + return reflect.DeepEqual( + expectedValue.Convert(actualType).Interface(), actual, + ) } - return false + // If BOTH values are numeric, there are chances of false positives due + // to overflow or underflow. So, we need to make sure to always convert + // the smaller type to a larger type before comparing. + if expectedType.Size() >= actualType.Size() { + return actualValue.Convert(expectedType).Interface() == expected + } + + return expectedValue.Convert(actualType).Interface() == actual +} + +// isNumericType returns true if the type is one of: +// int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, +// float32, float64, complex64, complex128 +func isNumericType(t reflect.Type) bool { + return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128 } /* CallerInfo is necessary because the assert functions use the testing object @@ -195,7 +296,7 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { // Aligns the provided message so that all lines after the first line start at the same location as the first line. // Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). -// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the +// The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the // basis on which the alignment occurs). func indentMessageLines(message string, longestLabelLen int) string { outBuf := new(bytes.Buffer) @@ -271,7 +372,7 @@ type labeledContent struct { // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: // -// \t{{label}}:{{align_spaces}}\t{{content}}\n +// \t{{label}}:{{align_spaces}}\t{{content}}\n // // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this @@ -294,7 +395,7 @@ func labeledOutput(content ...labeledContent) string { // Implements asserts that an object is implemented by the specified interface. // -// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -311,6 +412,25 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg return true } +// NotImplements asserts that an object does not implement the specified interface. +// +// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) +func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + interfaceType := reflect.TypeOf(interfaceObject).Elem() + + if object == nil { + return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...) + } + if reflect.TypeOf(object).Implements(interfaceType) { + return Fail(t, fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...) + } + + return true +} + // IsType asserts that the specified objects are of the same type. func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -326,7 +446,7 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs // Equal asserts that two objects are equal. // -// assert.Equal(t, 123, 123) +// assert.Equal(t, 123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -367,7 +487,7 @@ func validateEqualArgs(expected, actual interface{}) error { // Same asserts that two pointers reference the same object. // -// assert.Same(t, ptr1, ptr2) +// assert.Same(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -387,7 +507,7 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b // NotSame asserts that two pointers do not reference the same object. // -// assert.NotSame(t, ptr1, ptr2) +// assert.NotSame(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -425,7 +545,7 @@ func samePointers(first, second interface{}) bool { // representations appropriate to be presented to the user. // // If the values are not of like type, the returned strings will be prefixed -// with the type name, and the value will be enclosed in parenthesis similar +// with the type name, and the value will be enclosed in parentheses similar // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) { @@ -452,10 +572,10 @@ func truncatingFormat(data interface{}) string { return value } -// EqualValues asserts that two objects are equal or convertable to the same types +// EqualValues asserts that two objects are equal or convertible to the same types // and equal. // -// assert.EqualValues(t, uint32(123), int32(123)) +// assert.EqualValues(t, uint32(123), int32(123)) func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -473,9 +593,60 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa } +// EqualExportedValues asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true +// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false +func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + aType := reflect.TypeOf(expected) + bType := reflect.TypeOf(actual) + + if aType != bType { + return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) + } + + if aType.Kind() == reflect.Ptr { + aType = aType.Elem() + } + if bType.Kind() == reflect.Ptr { + bType = bType.Elem() + } + + if aType.Kind() != reflect.Struct { + return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", aType.Kind(), reflect.Struct), msgAndArgs...) + } + + if bType.Kind() != reflect.Struct { + return Fail(t, fmt.Sprintf("Types expected to both be struct or pointer to struct \n\t%v != %v", bType.Kind(), reflect.Struct), msgAndArgs...) + } + + expected = copyExportedFields(expected) + actual = copyExportedFields(actual) + + if !ObjectsAreEqualValues(expected, actual) { + diff := diff(expected, actual) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+ + "expected: %s\n"+ + "actual : %s%s", expected, actual, diff), msgAndArgs...) + } + + return true +} + // Exactly asserts that two objects are equal in value and type. // -// assert.Exactly(t, int32(123), int64(123)) +// assert.Exactly(t, int32(123), int64(123)) func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -494,7 +665,7 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} // NotNil asserts that the specified object is not nil. // -// assert.NotNil(t, err) +// assert.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if !isNil(object) { return true @@ -505,17 +676,6 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { return Fail(t, "Expected value not to be nil.", msgAndArgs...) } -// containsKind checks if a specified kind in the slice of kinds. -func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { - for i := 0; i < len(kinds); i++ { - if kind == kinds[i] { - return true - } - } - - return false -} - // isNil checks if a specified object is nil or not, without Failing. func isNil(object interface{}) bool { if object == nil { @@ -523,16 +683,13 @@ func isNil(object interface{}) bool { } value := reflect.ValueOf(object) - kind := value.Kind() - isNilableKind := containsKind( - []reflect.Kind{ - reflect.Chan, reflect.Func, - reflect.Interface, reflect.Map, - reflect.Ptr, reflect.Slice, reflect.UnsafePointer}, - kind) - - if isNilableKind && value.IsNil() { - return true + switch value.Kind() { + case + reflect.Chan, reflect.Func, + reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice, reflect.UnsafePointer: + + return value.IsNil() } return false @@ -540,7 +697,7 @@ func isNil(object interface{}) bool { // Nil asserts that the specified object is nil. // -// assert.Nil(t, err) +// assert.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if isNil(object) { return true @@ -583,7 +740,7 @@ func isEmpty(object interface{}) bool { // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Empty(t, obj) +// assert.Empty(t, obj) func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { pass := isEmpty(object) if !pass { @@ -600,9 +757,9 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { pass := !isEmpty(object) if !pass { @@ -616,40 +773,38 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { } -// getLen try to get length of object. -// return (false, 0) if impossible. -func getLen(x interface{}) (ok bool, length int) { +// getLen tries to get the length of an object. +// It returns (0, false) if impossible. +func getLen(x interface{}) (length int, ok bool) { v := reflect.ValueOf(x) defer func() { - if e := recover(); e != nil { - ok = false - } + ok = recover() == nil }() - return true, v.Len() + return v.Len(), true } // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// assert.Len(t, mySlice, 3) +// assert.Len(t, mySlice, 3) func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - ok, l := getLen(object) + l, ok := getLen(object) if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) + return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...) } if l != length { - return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) + return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) } return true } // True asserts that the specified value is true. // -// assert.True(t, myBool) +// assert.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { if !value { if h, ok := t.(tHelper); ok { @@ -664,7 +819,7 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { // False asserts that the specified value is false. // -// assert.False(t, myBool) +// assert.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { if value { if h, ok := t.(tHelper); ok { @@ -679,7 +834,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { // NotEqual asserts that the specified values are NOT equal. // -// assert.NotEqual(t, obj1, obj2) +// assert.NotEqual(t, obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -702,7 +857,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{ // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValues(t, obj1, obj2) +// assert.NotEqualValues(t, obj1, obj2) func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -761,9 +916,9 @@ func containsElement(list interface{}, element interface{}) (ok, found bool) { // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Contains(t, "Hello World", "World") -// assert.Contains(t, ["Hello", "World"], "World") -// assert.Contains(t, {"Hello": "World"}, "Hello") +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -784,9 +939,9 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContains(t, "Hello World", "Earth") -// assert.NotContains(t, ["Hello", "World"], "Earth") -// assert.NotContains(t, {"Hello": "World"}, "Earth") +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -794,20 +949,21 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) } if found { - return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...) } return true } -// Subset asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subset asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +// assert.Subset(t, [1, 2, 3], [1, 2]) +// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1}) func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() @@ -860,10 +1016,12 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return true } -// NotSubset asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubset asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +// assert.NotSubset(t, [1, 3, 4], [1, 2]) +// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3}) func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1048,7 +1206,7 @@ func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string // Panics asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panics(t, func(){ GoCrazy() }) +// assert.Panics(t, func(){ GoCrazy() }) func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1064,7 +1222,7 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1085,7 +1243,7 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1105,7 +1263,7 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs . // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanics(t, func(){ RemainCalm() }) +// assert.NotPanics(t, func(){ RemainCalm() }) func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1120,7 +1278,7 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { // WithinDuration asserts that the two times are within duration delta of each other. // -// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1136,7 +1294,7 @@ func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, // WithinRange asserts that a time is within a time range (inclusive). // -// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1195,7 +1353,7 @@ func toFloat(x interface{}) (float64, bool) { // InDelta asserts that the two numerals are within delta of each other. // -// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1324,7 +1482,7 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd h.Helper() } if math.IsNaN(epsilon) { - return Fail(t, "epsilon must not be NaN") + return Fail(t, "epsilon must not be NaN", msgAndArgs...) } actualEpsilon, err := calcRelativeError(expected, actual) if err != nil { @@ -1343,19 +1501,26 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m if h, ok := t.(tHelper); ok { h.Helper() } - if expected == nil || actual == nil || - reflect.TypeOf(actual).Kind() != reflect.Slice || - reflect.TypeOf(expected).Kind() != reflect.Slice { + + if expected == nil || actual == nil { return Fail(t, "Parameters must be slice", msgAndArgs...) } - actualSlice := reflect.ValueOf(actual) expectedSlice := reflect.ValueOf(expected) + actualSlice := reflect.ValueOf(actual) - for i := 0; i < actualSlice.Len(); i++ { - result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon) - if !result { - return result + if expectedSlice.Type().Kind() != reflect.Slice { + return Fail(t, "Expected value must be slice", msgAndArgs...) + } + + expectedLen := expectedSlice.Len() + if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) { + return false + } + + for i := 0; i < expectedLen; i++ { + if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) { + return false } } @@ -1368,10 +1533,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoError(t, err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if err != nil { if h, ok := t.(tHelper); ok { @@ -1385,10 +1550,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Error(t, err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { if err == nil { if h, ok := t.(tHelper); ok { @@ -1403,8 +1568,8 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualError(t, err, expectedErrorString) +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1426,8 +1591,8 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContains(t, err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1460,8 +1625,8 @@ func matchRegexp(rx interface{}, str interface{}) bool { // Regexp asserts that a specified regexp matches a string. // -// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") -// assert.Regexp(t, "start...$", "it's not starting") +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1478,8 +1643,8 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface // NotRegexp asserts that a specified regexp does not match a string. // -// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") -// assert.NotRegexp(t, "^start", "it's not starting") +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1591,7 +1756,7 @@ func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { // JSONEq asserts that two JSON strings are equivalent. // -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1714,7 +1879,7 @@ type tHelper interface { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1744,10 +1909,94 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t } } +// CollectT implements the TestingT interface and collects all errors. +type CollectT struct { + errors []error +} + +// Errorf collects the error. +func (c *CollectT) Errorf(format string, args ...interface{}) { + c.errors = append(c.errors, fmt.Errorf(format, args...)) +} + +// FailNow panics. +func (*CollectT) FailNow() { + panic("Assertion failed") +} + +// Deprecated: That was a method for internal usage that should not have been published. Now just panics. +func (*CollectT) Reset() { + panic("Reset() is deprecated") +} + +// Deprecated: That was a method for internal usage that should not have been published. Now just panics. +func (*CollectT) Copy(TestingT) { + panic("Copy() is deprecated") +} + +// EventuallyWithT asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// assert.EventuallyWithT(t, func(c *assert.CollectT) { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + var lastFinishedTickErrs []error + ch := make(chan []error, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + for _, err := range lastFinishedTickErrs { + t.Errorf("%v", err) + } + return Fail(t, "Condition never satisfied", msgAndArgs...) + case <-tick: + tick = nil + go func() { + collect := new(CollectT) + defer func() { + ch <- collect.errors + }() + condition(collect) + }() + case errs := <-ch: + if len(errs) == 0 { + return true + } + // Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached. + lastFinishedTickErrs = errs + tick = ticker.C + } + } +} + // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go index c9dccc4d6..4953981d3 100644 --- a/vendor/github.com/stretchr/testify/assert/doc.go +++ b/vendor/github.com/stretchr/testify/assert/doc.go @@ -1,39 +1,40 @@ // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. // -// Example Usage +// # Example Usage // // The following is a complete example using assert in a standard test function: -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// ) // -// func TestSomething(t *testing.T) { +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) // -// var a string = "Hello" -// var b string = "Hello" +// func TestSomething(t *testing.T) { // -// assert.Equal(t, a, b, "The two words should be the same.") +// var a string = "Hello" +// var b string = "Hello" // -// } +// assert.Equal(t, a, b, "The two words should be the same.") +// +// } // // if you assert many times, use the format below: // -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// ) +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) // -// func TestSomething(t *testing.T) { -// assert := assert.New(t) +// func TestSomething(t *testing.T) { +// assert := assert.New(t) // -// var a string = "Hello" -// var b string = "Hello" +// var a string = "Hello" +// var b string = "Hello" // -// assert.Equal(a, b, "The two words should be the same.") -// } +// assert.Equal(a, b, "The two words should be the same.") +// } // -// Assertions +// # Assertions // // Assertions allow you to easily write test code, and are global funcs in the `assert` package. // All assertion functions take, as the first argument, the `*testing.T` object provided by the diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go index 4ed341dd2..861ed4b7c 100644 --- a/vendor/github.com/stretchr/testify/assert/http_assertions.go +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -12,7 +12,7 @@ import ( // an error if building a new request fails. func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { w := httptest.NewRecorder() - req, err := http.NewRequest(method, url, nil) + req, err := http.NewRequest(method, url, http.NoBody) if err != nil { return -1, err } @@ -23,7 +23,7 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) ( // HTTPSuccess asserts that a specified handler returns a success status code. // -// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -32,12 +32,12 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent if !isSuccessCode { - Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) + Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) } return isSuccessCode @@ -45,7 +45,7 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -54,12 +54,12 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect if !isRedirectCode { - Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) + Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) } return isRedirectCode @@ -67,7 +67,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu // HTTPError asserts that a specified handler returns an error status code. // -// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { @@ -76,12 +76,12 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } isErrorCode := code >= http.StatusBadRequest if !isErrorCode { - Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) + Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) } return isErrorCode @@ -89,7 +89,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { @@ -98,12 +98,12 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va } code, err := httpCode(handler, method, url, values) if err != nil { - Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) } successful := code == statuscode if !successful { - Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code)) + Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...) } return successful @@ -113,7 +113,10 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, va // empty string if building a new request fails. func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { w := httptest.NewRecorder() - req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) + if len(values) > 0 { + url += "?" + values.Encode() + } + req, err := http.NewRequest(method, url, http.NoBody) if err != nil { return "" } @@ -124,7 +127,7 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -135,7 +138,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, contains := strings.Contains(body, fmt.Sprint(str)) if !contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...) } return contains @@ -144,7 +147,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { @@ -155,7 +158,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin contains := strings.Contains(body, fmt.Sprint(str)) if contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body), msgAndArgs...) } return !contains diff --git a/vendor/github.com/stretchr/testify/mock/doc.go b/vendor/github.com/stretchr/testify/mock/doc.go index 7324128ef..d6b3c844c 100644 --- a/vendor/github.com/stretchr/testify/mock/doc.go +++ b/vendor/github.com/stretchr/testify/mock/doc.go @@ -1,17 +1,17 @@ // Package mock provides a system by which it is possible to mock your objects // and verify calls are happening as expected. // -// Example Usage +// # Example Usage // // The mock package provides an object, Mock, that tracks activity on another object. It is usually // embedded into a test object as shown below: // -// type MyTestObject struct { -// // add a Mock object instance -// mock.Mock +// type MyTestObject struct { +// // add a Mock object instance +// mock.Mock // -// // other fields go here as normal -// } +// // other fields go here as normal +// } // // When implementing the methods of an interface, you wire your functions up // to call the Mock.Called(args...) method, and return the appropriate values. @@ -19,25 +19,25 @@ // For example, to mock a method that saves the name and age of a person and returns // the year of their birth or an error, you might write this: // -// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { -// args := o.Called(firstname, lastname, age) -// return args.Int(0), args.Error(1) -// } +// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { +// args := o.Called(firstname, lastname, age) +// return args.Int(0), args.Error(1) +// } // // The Int, Error and Bool methods are examples of strongly typed getters that take the argument // index position. Given this argument list: // -// (12, true, "Something") +// (12, true, "Something") // // You could read them out strongly typed like this: // -// args.Int(0) -// args.Bool(1) -// args.String(2) +// args.Int(0) +// args.Bool(1) +// args.String(2) // // For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: // -// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) +// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) // // This may cause a panic if the object you are getting is nil (the type assertion will fail), in those // cases you should check for nil first. diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go index e6ff8dfeb..213bde2ea 100644 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -3,6 +3,7 @@ package mock import ( "errors" "fmt" + "path" "reflect" "regexp" "runtime" @@ -13,9 +14,13 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/pmezard/go-difflib/difflib" "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" ) +// regex for GCCGO functions +var gccgoRE = regexp.MustCompile(`\.pN\d+_`) + // TestingT is an interface wrapper around *testing.T type TestingT interface { Logf(format string, args ...interface{}) @@ -99,7 +104,7 @@ func (c *Call) unlock() { // Return specifies the return arguments for the expectation. // -// Mock.On("DoSomething").Return(errors.New("failed")) +// Mock.On("DoSomething").Return(errors.New("failed")) func (c *Call) Return(returnArguments ...interface{}) *Call { c.lock() defer c.unlock() @@ -109,9 +114,9 @@ func (c *Call) Return(returnArguments ...interface{}) *Call { return c } -// Panic specifies if the functon call should fail and the panic message +// Panic specifies if the function call should fail and the panic message // -// Mock.On("DoSomething").Panic("test panic") +// Mock.On("DoSomething").Panic("test panic") func (c *Call) Panic(msg string) *Call { c.lock() defer c.unlock() @@ -121,24 +126,24 @@ func (c *Call) Panic(msg string) *Call { return c } -// Once indicates that that the mock should only return the value once. +// Once indicates that the mock should only return the value once. // -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() func (c *Call) Once() *Call { return c.Times(1) } -// Twice indicates that that the mock should only return the value twice. +// Twice indicates that the mock should only return the value twice. // -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() func (c *Call) Twice() *Call { return c.Times(2) } -// Times indicates that that the mock should only return the indicated number +// Times indicates that the mock should only return the indicated number // of times. // -// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) func (c *Call) Times(i int) *Call { c.lock() defer c.unlock() @@ -149,7 +154,7 @@ func (c *Call) Times(i int) *Call { // WaitUntil sets the channel that will block the mock's return until its closed // or a message is received. // -// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) +// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) func (c *Call) WaitUntil(w <-chan time.Time) *Call { c.lock() defer c.unlock() @@ -159,7 +164,7 @@ func (c *Call) WaitUntil(w <-chan time.Time) *Call { // After sets how long to block until the call returns // -// Mock.On("MyMethod", arg1, arg2).After(time.Second) +// Mock.On("MyMethod", arg1, arg2).After(time.Second) func (c *Call) After(d time.Duration) *Call { c.lock() defer c.unlock() @@ -171,10 +176,10 @@ func (c *Call) After(d time.Duration) *Call { // mocking a method (such as an unmarshaler) that takes a pointer to a struct and // sets properties in such struct // -// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) { -// arg := args.Get(0).(*map[string]interface{}) -// arg["foo"] = "bar" -// }) +// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) { +// arg := args.Get(0).(*map[string]interface{}) +// arg["foo"] = "bar" +// }) func (c *Call) Run(fn func(args Arguments)) *Call { c.lock() defer c.unlock() @@ -194,16 +199,18 @@ func (c *Call) Maybe() *Call { // On chains a new expectation description onto the mocked interface. This // allows syntax like. // -// Mock. -// On("MyMethod", 1).Return(nil). -// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) +// Mock. +// On("MyMethod", 1).Return(nil). +// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) +// //go:noinline func (c *Call) On(methodName string, arguments ...interface{}) *Call { return c.Parent.On(methodName, arguments...) } // Unset removes a mock handler from being called. -// test.On("func", mock.Anything).Unset() +// +// test.On("func", mock.Anything).Unset() func (c *Call) Unset() *Call { var unlockOnce sync.Once @@ -249,9 +256,9 @@ func (c *Call) Unset() *Call { // calls have been called as expected. The referenced calls may be from the // same mock instance and/or other mock instances. // -// Mock.On("Do").Return(nil).Notbefore( -// Mock.On("Init").Return(nil) -// ) +// Mock.On("Do").Return(nil).Notbefore( +// Mock.On("Init").Return(nil) +// ) func (c *Call) NotBefore(calls ...*Call) *Call { c.lock() defer c.unlock() @@ -334,7 +341,7 @@ func (m *Mock) fail(format string, args ...interface{}) { // On starts a description of an expectation of the specified method // being called. // -// Mock.On("MyMethod", arg1, arg2) +// Mock.On("MyMethod", arg1, arg2) func (m *Mock) On(methodName string, arguments ...interface{}) *Call { for _, arg := range arguments { if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { @@ -424,6 +431,10 @@ func callString(method string, arguments Arguments, includeArgumentValues bool) if includeArgumentValues { var argVals []string for argIndex, arg := range arguments { + if _, ok := arg.(*FunctionalOptionsArgument); ok { + argVals = append(argVals, fmt.Sprintf("%d: %s", argIndex, arg)) + continue + } argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) } argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) @@ -447,9 +458,8 @@ func (m *Mock) Called(arguments ...interface{}) Arguments { // For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock // uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree // With GCCGO we need to remove interface information starting from pN

. - re := regexp.MustCompile("\\.pN\\d+_") - if re.MatchString(functionPath) { - functionPath = re.Split(functionPath, -1)[0] + if gccgoRE.MatchString(functionPath) { + functionPath = gccgoRE.Split(functionPath, -1)[0] } parts := strings.Split(functionPath, ".") functionName := parts[len(parts)-1] @@ -466,7 +476,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen found, call := m.findExpectedCall(methodName, arguments...) if found < 0 { - // expected call found but it has already been called with repeatable times + // expected call found, but it has already been called with repeatable times if call != nil { m.mutex.Unlock() m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(\"%s\").Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo()) @@ -555,7 +565,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen Assertions */ -type assertExpectationser interface { +type assertExpectationiser interface { AssertExpectations(TestingT) bool } @@ -572,7 +582,7 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") obj = m } - m := obj.(assertExpectationser) + m := obj.(assertExpectationiser) if !m.AssertExpectations(t) { t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) return false @@ -584,6 +594,9 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { // AssertExpectations asserts that everything specified with On and Return was // in fact called as expected. Calls may have occurred in any order. func (m *Mock) AssertExpectations(t TestingT) bool { + if s, ok := t.(interface{ Skipped() bool }); ok && s.Skipped() { + return true + } if h, ok := t.(tHelper); ok { h.Helper() } @@ -598,8 +611,8 @@ func (m *Mock) AssertExpectations(t TestingT) bool { satisfied, reason := m.checkExpectation(expectedCall) if !satisfied { failedExpectations++ + t.Logf(reason) } - t.Logf(reason) } if failedExpectations != 0 { @@ -750,24 +763,33 @@ const ( Anything = "mock.Anything" ) -// AnythingOfTypeArgument is a string that contains the type of an argument +// AnythingOfTypeArgument contains the type of an argument +// for use when type checking. Used in Diff and Assert. +// +// Deprecated: this is an implementation detail that must not be used. Use [AnythingOfType] instead. +type AnythingOfTypeArgument = anythingOfTypeArgument + +// anythingOfTypeArgument is a string that contains the type of an argument // for use when type checking. Used in Diff and Assert. -type AnythingOfTypeArgument string +type anythingOfTypeArgument string -// AnythingOfType returns an AnythingOfTypeArgument object containing the -// name of the type to check for. Used in Diff and Assert. +// AnythingOfType returns a special value containing the +// name of the type to check for. The type name will be matched against the type name returned by [reflect.Type.String]. +// +// Used in Diff and Assert. // // For example: +// // Assert(t, AnythingOfType("string"), AnythingOfType("int")) func AnythingOfType(t string) AnythingOfTypeArgument { - return AnythingOfTypeArgument(t) + return anythingOfTypeArgument(t) } // IsTypeArgument is a struct that contains the type of an argument // for use when type checking. This is an alternative to AnythingOfType. // Used in Diff and Assert. type IsTypeArgument struct { - t interface{} + t reflect.Type } // IsType returns an IsTypeArgument object containing the type to check for. @@ -777,7 +799,35 @@ type IsTypeArgument struct { // For example: // Assert(t, IsType(""), IsType(0)) func IsType(t interface{}) *IsTypeArgument { - return &IsTypeArgument{t: t} + return &IsTypeArgument{t: reflect.TypeOf(t)} +} + +// FunctionalOptionsArgument is a struct that contains the type and value of an functional option argument +// for use when type checking. +type FunctionalOptionsArgument struct { + value interface{} +} + +// String returns the string representation of FunctionalOptionsArgument +func (f *FunctionalOptionsArgument) String() string { + var name string + tValue := reflect.ValueOf(f.value) + if tValue.Len() > 0 { + name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String() + } + + return strings.Replace(fmt.Sprintf("%#v", f.value), "[]interface {}", name, 1) +} + +// FunctionalOptions returns an FunctionalOptionsArgument object containing the functional option type +// and the values to check of +// +// For example: +// Assert(t, FunctionalOptions("[]foo.FunctionalOption", foo.Opt1(), foo.Opt2())) +func FunctionalOptions(value ...interface{}) *FunctionalOptionsArgument { + return &FunctionalOptionsArgument{ + value: value, + } } // argumentMatcher performs custom argument matching, returning whether or @@ -913,29 +963,54 @@ func (args Arguments) Diff(objects []interface{}) (string, int) { differences++ output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher) } - } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { - // type checking - if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { - // not match - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) - } - } else if reflect.TypeOf(expected) == reflect.TypeOf((*IsTypeArgument)(nil)) { - t := expected.(*IsTypeArgument).t - if reflect.TypeOf(t) != reflect.TypeOf(actual) { - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt) - } } else { - // normal checking + switch expected := expected.(type) { + case anythingOfTypeArgument: + // type checking + if reflect.TypeOf(actual).Name() != string(expected) && reflect.TypeOf(actual).String() != string(expected) { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) + } + case *IsTypeArgument: + actualT := reflect.TypeOf(actual) + if actualT != expected.t { + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected.t.Name(), actualT.Name(), actualFmt) + } + case *FunctionalOptionsArgument: + t := expected.value - if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { - // match - output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) - } else { - // not match - differences++ - output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) + var name string + tValue := reflect.ValueOf(t) + if tValue.Len() > 0 { + name = "[]" + reflect.TypeOf(tValue.Index(0).Interface()).String() + } + + tName := reflect.TypeOf(t).Name() + if name != reflect.TypeOf(actual).String() && tValue.Len() != 0 { + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, tName, reflect.TypeOf(actual).Name(), actualFmt) + } else { + if ef, af := assertOpts(t, actual); ef == "" && af == "" { + // match + output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, tName, tName) + } else { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, af, ef) + } + } + + default: + if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { + // match + output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) + } else { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) + } } } @@ -1102,3 +1177,65 @@ var spewConfig = spew.ConfigState{ type tHelper interface { Helper() } + +func assertOpts(expected, actual interface{}) (expectedFmt, actualFmt string) { + expectedOpts := reflect.ValueOf(expected) + actualOpts := reflect.ValueOf(actual) + var expectedNames []string + for i := 0; i < expectedOpts.Len(); i++ { + expectedNames = append(expectedNames, funcName(expectedOpts.Index(i).Interface())) + } + var actualNames []string + for i := 0; i < actualOpts.Len(); i++ { + actualNames = append(actualNames, funcName(actualOpts.Index(i).Interface())) + } + if !assert.ObjectsAreEqual(expectedNames, actualNames) { + expectedFmt = fmt.Sprintf("%v", expectedNames) + actualFmt = fmt.Sprintf("%v", actualNames) + return + } + + for i := 0; i < expectedOpts.Len(); i++ { + expectedOpt := expectedOpts.Index(i).Interface() + actualOpt := actualOpts.Index(i).Interface() + + expectedFunc := expectedNames[i] + actualFunc := actualNames[i] + if expectedFunc != actualFunc { + expectedFmt = expectedFunc + actualFmt = actualFunc + return + } + + ot := reflect.TypeOf(expectedOpt) + var expectedValues []reflect.Value + var actualValues []reflect.Value + if ot.NumIn() == 0 { + return + } + + for i := 0; i < ot.NumIn(); i++ { + vt := ot.In(i).Elem() + expectedValues = append(expectedValues, reflect.New(vt)) + actualValues = append(actualValues, reflect.New(vt)) + } + + reflect.ValueOf(expectedOpt).Call(expectedValues) + reflect.ValueOf(actualOpt).Call(actualValues) + + for i := 0; i < ot.NumIn(); i++ { + if !assert.ObjectsAreEqual(expectedValues[i].Interface(), actualValues[i].Interface()) { + expectedFmt = fmt.Sprintf("%s %+v", expectedNames[i], expectedValues[i].Interface()) + actualFmt = fmt.Sprintf("%s %+v", expectedNames[i], actualValues[i].Interface()) + return + } + } + } + + return "", "" +} + +func funcName(opt interface{}) string { + n := runtime.FuncForPC(reflect.ValueOf(opt).Pointer()).Name() + return strings.TrimSuffix(path.Base(n), path.Ext(n)) +} diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go index 169de3922..968434724 100644 --- a/vendor/github.com/stretchr/testify/require/doc.go +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -1,24 +1,25 @@ // Package require implements the same assertions as the `assert` package but // stops test execution when a test fails. // -// Example Usage +// # Example Usage // // The following is a complete example using require in a standard test function: -// import ( -// "testing" -// "github.com/stretchr/testify/require" -// ) // -// func TestSomething(t *testing.T) { +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) // -// var a string = "Hello" -// var b string = "Hello" +// func TestSomething(t *testing.T) { // -// require.Equal(t, a, b, "The two words should be the same.") +// var a string = "Hello" +// var b string = "Hello" // -// } +// require.Equal(t, a, b, "The two words should be the same.") // -// Assertions +// } +// +// # Assertions // // The `require` package have same global functions as in the `assert` package, // but instead of returning a boolean result they call `t.FailNow()`. diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go index 880853f5a..506a82f80 100644 --- a/vendor/github.com/stretchr/testify/require/require.go +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -1,7 +1,4 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND - */ +// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package require @@ -37,9 +34,9 @@ func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interfac // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Contains(t, "Hello World", "World") -// assert.Contains(t, ["Hello", "World"], "World") -// assert.Contains(t, {"Hello": "World"}, "Hello") +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -53,9 +50,9 @@ func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...int // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") -// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") -// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -123,7 +120,7 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Empty(t, obj) +// assert.Empty(t, obj) func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -137,7 +134,7 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// assert.Emptyf(t, obj, "error message %s", "formatted") +// assert.Emptyf(t, obj, "error message %s", "formatted") func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -150,7 +147,7 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { // Equal asserts that two objects are equal. // -// assert.Equal(t, 123, 123) +// assert.Equal(t, 123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -168,8 +165,8 @@ func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...i // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualError(t, err, expectedErrorString) +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -183,8 +180,8 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -195,10 +192,50 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args t.FailNow() } -// EqualValues asserts that two objects are equal or convertable to the same types +// EqualExportedValues asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true +// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false +func EqualExportedValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualExportedValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualExportedValuesf asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true +// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false +func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualExportedValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// EqualValues asserts that two objects are equal or convertible to the same types // and equal. // -// assert.EqualValues(t, uint32(123), int32(123)) +// assert.EqualValues(t, uint32(123), int32(123)) func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -209,10 +246,10 @@ func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArg t.FailNow() } -// EqualValuesf asserts that two objects are equal or convertable to the same types +// EqualValuesf asserts that two objects are equal or convertible to the same types // and equal. // -// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -225,7 +262,7 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri // Equalf asserts that two objects are equal. // -// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// assert.Equalf(t, 123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -242,10 +279,10 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Error(t, err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } func Error(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -283,8 +320,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContains(t, err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -298,8 +335,8 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -336,10 +373,10 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if assert.Errorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func Errorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -353,7 +390,7 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -364,10 +401,66 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t t.FailNow() } +// EventuallyWithT asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// assert.EventuallyWithT(t, func(c *assert.CollectT) { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// EventuallyWithTf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -380,7 +473,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick // Exactly asserts that two objects are equal in value and type. // -// assert.Exactly(t, int32(123), int64(123)) +// assert.Exactly(t, int32(123), int64(123)) func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -393,7 +486,7 @@ func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs .. // Exactlyf asserts that two objects are equal in value and type. // -// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -450,7 +543,7 @@ func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { // False asserts that the specified value is false. // -// assert.False(t, myBool) +// assert.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -463,7 +556,7 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) { // Falsef asserts that the specified value is false. // -// assert.Falsef(t, myBool, "error message %s", "formatted") +// assert.Falsef(t, myBool, "error message %s", "formatted") func Falsef(t TestingT, value bool, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -500,9 +593,9 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { // Greater asserts that the first element is greater than the second // -// assert.Greater(t, 2, 1) -// assert.Greater(t, float64(2), float64(1)) -// assert.Greater(t, "b", "a") +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -515,10 +608,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqual(t, 2, 1) -// assert.GreaterOrEqual(t, 2, 2) -// assert.GreaterOrEqual(t, "b", "a") -// assert.GreaterOrEqual(t, "b", "b") +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -531,10 +624,10 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") -// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -547,9 +640,9 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg // Greaterf asserts that the first element is greater than the second // -// assert.Greaterf(t, 2, 1, "error message %s", "formatted") -// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") -// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -563,7 +656,7 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -579,7 +672,7 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -595,7 +688,7 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -611,7 +704,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -626,7 +719,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // HTTPError asserts that a specified handler returns an error status code. // -// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -641,7 +734,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPErrorf asserts that a specified handler returns an error status code. // -// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -656,7 +749,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -671,7 +764,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -686,7 +779,7 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { @@ -701,7 +794,7 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url str // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { @@ -716,7 +809,7 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st // HTTPSuccess asserts that a specified handler returns a success status code. // -// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -731,7 +824,7 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string // HTTPSuccessf asserts that a specified handler returns a success status code. // -// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -746,7 +839,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin // Implements asserts that an object is implemented by the specified interface. // -// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -759,7 +852,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg // Implementsf asserts that an object is implemented by the specified interface. // -// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -772,7 +865,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms // InDelta asserts that the two numerals are within delta of each other. // -// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -829,7 +922,7 @@ func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta f // InDeltaf asserts that the two numerals are within delta of each other. // -// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -886,9 +979,9 @@ func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon fl // IsDecreasing asserts that the collection is decreasing // -// assert.IsDecreasing(t, []int{2, 1, 0}) -// assert.IsDecreasing(t, []float{2, 1}) -// assert.IsDecreasing(t, []string{"b", "a"}) +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -901,9 +994,9 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { // IsDecreasingf asserts that the collection is decreasing // -// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -916,9 +1009,9 @@ func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface // IsIncreasing asserts that the collection is increasing // -// assert.IsIncreasing(t, []int{1, 2, 3}) -// assert.IsIncreasing(t, []float{1, 2}) -// assert.IsIncreasing(t, []string{"a", "b"}) +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -931,9 +1024,9 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { // IsIncreasingf asserts that the collection is increasing // -// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -946,9 +1039,9 @@ func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface // IsNonDecreasing asserts that the collection is not decreasing // -// assert.IsNonDecreasing(t, []int{1, 1, 2}) -// assert.IsNonDecreasing(t, []float{1, 2}) -// assert.IsNonDecreasing(t, []string{"a", "b"}) +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -961,9 +1054,9 @@ func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // IsNonDecreasingf asserts that the collection is not decreasing // -// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") -// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -976,9 +1069,9 @@ func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interf // IsNonIncreasing asserts that the collection is not increasing // -// assert.IsNonIncreasing(t, []int{2, 1, 1}) -// assert.IsNonIncreasing(t, []float{2, 1}) -// assert.IsNonIncreasing(t, []string{"b", "a"}) +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -991,9 +1084,9 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // IsNonIncreasingf asserts that the collection is not increasing // -// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") -// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1028,7 +1121,7 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin // JSONEq asserts that two JSON strings are equivalent. // -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1041,7 +1134,7 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ // JSONEqf asserts that two JSON strings are equivalent. // -// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1055,7 +1148,7 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// assert.Len(t, mySlice, 3) +// assert.Len(t, mySlice, 3) func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1069,7 +1162,7 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1082,9 +1175,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf // Less asserts that the first element is less than the second // -// assert.Less(t, 1, 2) -// assert.Less(t, float64(1), float64(2)) -// assert.Less(t, "a", "b") +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1097,10 +1190,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) // LessOrEqual asserts that the first element is less than or equal to the second // -// assert.LessOrEqual(t, 1, 2) -// assert.LessOrEqual(t, 2, 2) -// assert.LessOrEqual(t, "a", "b") -// assert.LessOrEqual(t, "b", "b") +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1113,10 +1206,10 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter // LessOrEqualf asserts that the first element is less than or equal to the second // -// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") -// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") -// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1129,9 +1222,9 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . // Lessf asserts that the first element is less than the second // -// assert.Lessf(t, 1, 2, "error message %s", "formatted") -// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") -// assert.Lessf(t, "a", "b", "error message %s", "formatted") +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1144,8 +1237,8 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter // Negative asserts that the specified element is negative // -// assert.Negative(t, -1) -// assert.Negative(t, -1.23) +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1158,8 +1251,8 @@ func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { // Negativef asserts that the specified element is negative // -// assert.Negativef(t, -1, "error message %s", "formatted") -// assert.Negativef(t, -1.23, "error message %s", "formatted") +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1173,7 +1266,7 @@ func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1187,7 +1280,7 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1200,7 +1293,7 @@ func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time. // Nil asserts that the specified object is nil. // -// assert.Nil(t, err) +// assert.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1213,7 +1306,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { // Nilf asserts that the specified object is nil. // -// assert.Nilf(t, err, "error message %s", "formatted") +// assert.Nilf(t, err, "error message %s", "formatted") func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1250,10 +1343,10 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoError(t, err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } func NoError(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1266,10 +1359,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) { // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if assert.NoErrorf(t, err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1307,9 +1400,9 @@ func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContains(t, "Hello World", "Earth") -// assert.NotContains(t, ["Hello", "World"], "Earth") -// assert.NotContains(t, {"Hello": "World"}, "Earth") +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1323,9 +1416,9 @@ func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ... // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") -// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1339,9 +1432,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmpty(t, obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1355,9 +1448,9 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1370,7 +1463,7 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) // NotEqual asserts that the specified values are NOT equal. // -// assert.NotEqual(t, obj1, obj2) +// assert.NotEqual(t, obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1386,7 +1479,7 @@ func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs . // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValues(t, obj1, obj2) +// assert.NotEqualValues(t, obj1, obj2) func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1399,7 +1492,7 @@ func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAnd // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1412,7 +1505,7 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s // NotEqualf asserts that the specified values are NOT equal. // -// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1450,9 +1543,35 @@ func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interf t.FailNow() } +// NotImplements asserts that an object does not implement the specified interface. +// +// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject)) +func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotImplements(t, interfaceObject, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotImplementsf asserts that an object does not implement the specified interface. +// +// assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotImplementsf(t, interfaceObject, object, msg, args...) { + return + } + t.FailNow() +} + // NotNil asserts that the specified object is not nil. // -// assert.NotNil(t, err) +// assert.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1465,7 +1584,7 @@ func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { // NotNilf asserts that the specified object is not nil. // -// assert.NotNilf(t, err, "error message %s", "formatted") +// assert.NotNilf(t, err, "error message %s", "formatted") func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1478,7 +1597,7 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanics(t, func(){ RemainCalm() }) +// assert.NotPanics(t, func(){ RemainCalm() }) func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1491,7 +1610,7 @@ func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1504,8 +1623,8 @@ func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interfac // NotRegexp asserts that a specified regexp does not match a string. // -// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") -// assert.NotRegexp(t, "^start", "it's not starting") +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1518,8 +1637,8 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf // NotRegexpf asserts that a specified regexp does not match a string. // -// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1532,7 +1651,7 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args .. // NotSame asserts that two pointers do not reference the same object. // -// assert.NotSame(t, ptr1, ptr2) +// assert.NotSame(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1548,7 +1667,7 @@ func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs .. // NotSamef asserts that two pointers do not reference the same object. // -// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1562,10 +1681,12 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } -// NotSubset asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubset asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +// assert.NotSubset(t, [1, 3, 4], [1, 2]) +// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3}) func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1576,10 +1697,12 @@ func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...i t.FailNow() } -// NotSubsetf asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubsetf asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted") +// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1614,7 +1737,7 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { // Panics asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panics(t, func(){ GoCrazy() }) +// assert.Panics(t, func(){ GoCrazy() }) func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1629,7 +1752,7 @@ func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1644,7 +1767,7 @@ func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAn // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1658,7 +1781,7 @@ func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1672,7 +1795,7 @@ func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, m // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1685,7 +1808,7 @@ func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1698,8 +1821,8 @@ func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{} // Positive asserts that the specified element is positive // -// assert.Positive(t, 1) -// assert.Positive(t, 1.23) +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1712,8 +1835,8 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { // Positivef asserts that the specified element is positive // -// assert.Positivef(t, 1, "error message %s", "formatted") -// assert.Positivef(t, 1.23, "error message %s", "formatted") +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1726,8 +1849,8 @@ func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { // Regexp asserts that a specified regexp matches a string. // -// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") -// assert.Regexp(t, "start...$", "it's not starting") +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1740,8 +1863,8 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface // Regexpf asserts that a specified regexp matches a string. // -// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1754,7 +1877,7 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in // Same asserts that two pointers reference the same object. // -// assert.Same(t, ptr1, ptr2) +// assert.Same(t, ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1770,7 +1893,7 @@ func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...in // Samef asserts that two pointers reference the same object. // -// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1784,10 +1907,11 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg t.FailNow() } -// Subset asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subset asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +// assert.Subset(t, [1, 2, 3], [1, 2]) +// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1}) func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1798,10 +1922,11 @@ func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...inte t.FailNow() } -// Subsetf asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subsetf asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted") +// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1814,7 +1939,7 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args // True asserts that the specified value is true. // -// assert.True(t, myBool) +// assert.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1827,7 +1952,7 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) { // Truef asserts that the specified value is true. // -// assert.Truef(t, myBool, "error message %s", "formatted") +// assert.Truef(t, myBool, "error message %s", "formatted") func Truef(t TestingT, value bool, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1840,7 +1965,7 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) { // WithinDuration asserts that the two times are within duration delta of each other. // -// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1853,7 +1978,7 @@ func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time // WithinDurationf asserts that the two times are within duration delta of each other. // -// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1866,7 +1991,7 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim // WithinRange asserts that a time is within a time range (inclusive). // -// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1879,7 +2004,7 @@ func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, m // WithinRangef asserts that a time is within a time range (inclusive). // -// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go index 960bf6f2c..eee8310a5 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -1,7 +1,4 @@ -/* -* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen -* THIS FILE MUST NOT BE EDITED BY HAND - */ +// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT. package require @@ -31,9 +28,9 @@ func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...inte // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Contains("Hello World", "World") -// a.Contains(["Hello", "World"], "World") -// a.Contains({"Hello": "World"}, "Hello") +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -44,9 +41,9 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs .. // Containsf asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. // -// a.Containsf("Hello World", "World", "error message %s", "formatted") -// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") -// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -99,7 +96,7 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Empty(obj) +// a.Empty(obj) func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -110,7 +107,7 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { // Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. // -// a.Emptyf(obj, "error message %s", "formatted") +// a.Emptyf(obj, "error message %s", "formatted") func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -120,7 +117,7 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) // Equal asserts that two objects are equal. // -// a.Equal(123, 123) +// a.Equal(123, 123) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -135,8 +132,8 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualError(err, expectedErrorString) +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -147,8 +144,8 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... // EqualErrorf asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. // -// actualObj, err := SomeFunction() -// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -156,10 +153,44 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a EqualErrorf(a.t, theError, errString, msg, args...) } -// EqualValues asserts that two objects are equal or convertable to the same types +// EqualExportedValues asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true +// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false +func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualExportedValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualExportedValuesf asserts that the types of two objects are equal and their public +// fields are also equal. This is useful for comparing structs that have private fields +// that could potentially differ. +// +// type S struct { +// Exported int +// notExported int +// } +// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true +// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false +func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualExportedValuesf(a.t, expected, actual, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertible to the same types // and equal. // -// a.EqualValues(uint32(123), int32(123)) +// a.EqualValues(uint32(123), int32(123)) func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -167,10 +198,10 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn EqualValues(a.t, expected, actual, msgAndArgs...) } -// EqualValuesf asserts that two objects are equal or convertable to the same types +// EqualValuesf asserts that two objects are equal or convertible to the same types // and equal. // -// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -180,7 +211,7 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg // Equalf asserts that two objects are equal. // -// a.Equalf(123, 123, "error message %s", "formatted") +// a.Equalf(123, 123, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). Function equality @@ -194,10 +225,10 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string // Error asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Error(err) { -// assert.Equal(t, expectedError, err) -// } +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -226,8 +257,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. // ErrorContains asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContains(err, expectedErrorSubString) +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -238,8 +269,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) // and that the error contains the specified substring. // -// actualObj, err := SomeFunction() -// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -267,10 +298,10 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter // Errorf asserts that a function returned an error (i.e. not `nil`). // -// actualObj, err := SomeFunction() -// if a.Errorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedErrorf, err) -// } +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -281,7 +312,7 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { // Eventually asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -289,10 +320,60 @@ func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, ti Eventually(a.t, condition, waitFor, tick, msgAndArgs...) } +// EventuallyWithT asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// a.EventuallyWithT(func(c *assert.CollectT) { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// EventuallyWithTf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. In contrast to Eventually, +// it supplies a CollectT to the condition function, so that the condition +// function can use the CollectT to call other assertions. +// The condition is considered "met" if no errors are raised in a tick. +// The supplied CollectT collects all errors from one tick (if there are any). +// If the condition is not met before waitFor, the collected errors of +// the last tick are copied to t. +// +// externalValue := false +// go func() { +// time.Sleep(8*time.Second) +// externalValue = true +// }() +// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { +// // add assertions as needed; any assertion failure will fail the current tick +// assert.True(c, externalValue, "expected 'externalValue' to be true") +// }, 1*time.Second, 10*time.Second, "external state has not changed to 'true'; still false") +func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...) +} + // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // -// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -302,7 +383,7 @@ func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, t // Exactly asserts that two objects are equal in value and type. // -// a.Exactly(int32(123), int64(123)) +// a.Exactly(int32(123), int64(123)) func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -312,7 +393,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg // Exactlyf asserts that two objects are equal in value and type. // -// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -354,7 +435,7 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{ // False asserts that the specified value is false. // -// a.False(myBool) +// a.False(myBool) func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -364,7 +445,7 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { // Falsef asserts that the specified value is false. // -// a.Falsef(myBool, "error message %s", "formatted") +// a.Falsef(myBool, "error message %s", "formatted") func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -392,9 +473,9 @@ func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { // Greater asserts that the first element is greater than the second // -// a.Greater(2, 1) -// a.Greater(float64(2), float64(1)) -// a.Greater("b", "a") +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -404,10 +485,10 @@ func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...inter // GreaterOrEqual asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqual(2, 1) -// a.GreaterOrEqual(2, 2) -// a.GreaterOrEqual("b", "a") -// a.GreaterOrEqual("b", "b") +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -417,10 +498,10 @@ func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs . // GreaterOrEqualf asserts that the first element is greater than or equal to the second // -// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") -// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") -// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") -// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -430,9 +511,9 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, // Greaterf asserts that the first element is greater than the second // -// a.Greaterf(2, 1, "error message %s", "formatted") -// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") -// a.Greaterf("b", "a", "error message %s", "formatted") +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -443,7 +524,7 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args . // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -456,7 +537,7 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u // HTTPBodyContainsf asserts that a specified handler returns a // body that contains a string. // -// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -469,7 +550,7 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { @@ -482,7 +563,7 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string // HTTPBodyNotContainsf asserts that a specified handler returns a // body that does not contain a string. // -// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { @@ -494,7 +575,7 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin // HTTPError asserts that a specified handler returns an error status code. // -// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -506,7 +587,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // HTTPErrorf asserts that a specified handler returns an error status code. // -// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -518,7 +599,7 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str // HTTPRedirect asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -530,7 +611,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // HTTPRedirectf asserts that a specified handler returns a redirect status code. // -// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -542,7 +623,7 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url // HTTPStatusCode asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { @@ -554,7 +635,7 @@ func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url // HTTPStatusCodef asserts that a specified handler returns a specified status code. // -// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { @@ -566,7 +647,7 @@ func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, ur // HTTPSuccess asserts that a specified handler returns a success status code. // -// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { @@ -578,7 +659,7 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // -// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") // // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { @@ -590,7 +671,7 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s // Implements asserts that an object is implemented by the specified interface. // -// a.Implements((*MyInterface)(nil), new(MyObject)) +// a.Implements((*MyInterface)(nil), new(MyObject)) func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -600,7 +681,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, // Implementsf asserts that an object is implemented by the specified interface. // -// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -610,7 +691,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{} // InDelta asserts that the two numerals are within delta of each other. // -// a.InDelta(math.Pi, 22/7.0, 0.01) +// a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -652,7 +733,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del // InDeltaf asserts that the two numerals are within delta of each other. // -// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -694,9 +775,9 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo // IsDecreasing asserts that the collection is decreasing // -// a.IsDecreasing([]int{2, 1, 0}) -// a.IsDecreasing([]float{2, 1}) -// a.IsDecreasing([]string{"b", "a"}) +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -706,9 +787,9 @@ func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) // IsDecreasingf asserts that the collection is decreasing // -// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") -// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -718,9 +799,9 @@ func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...inter // IsIncreasing asserts that the collection is increasing // -// a.IsIncreasing([]int{1, 2, 3}) -// a.IsIncreasing([]float{1, 2}) -// a.IsIncreasing([]string{"a", "b"}) +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -730,9 +811,9 @@ func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) // IsIncreasingf asserts that the collection is increasing // -// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") -// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -742,9 +823,9 @@ func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...inter // IsNonDecreasing asserts that the collection is not decreasing // -// a.IsNonDecreasing([]int{1, 1, 2}) -// a.IsNonDecreasing([]float{1, 2}) -// a.IsNonDecreasing([]string{"a", "b"}) +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -754,9 +835,9 @@ func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface // IsNonDecreasingf asserts that the collection is not decreasing // -// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") -// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -766,9 +847,9 @@ func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...in // IsNonIncreasing asserts that the collection is not increasing // -// a.IsNonIncreasing([]int{2, 1, 1}) -// a.IsNonIncreasing([]float{2, 1}) -// a.IsNonIncreasing([]string{"b", "a"}) +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -778,9 +859,9 @@ func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface // IsNonIncreasingf asserts that the collection is not increasing // -// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") -// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -806,7 +887,7 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s // JSONEq asserts that two JSON strings are equivalent. // -// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -816,7 +897,7 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf // JSONEqf asserts that two JSON strings are equivalent. // -// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -827,7 +908,7 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // -// a.Len(mySlice, 3) +// a.Len(mySlice, 3) func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -838,7 +919,7 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // -// a.Lenf(mySlice, 3, "error message %s", "formatted") +// a.Lenf(mySlice, 3, "error message %s", "formatted") func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -848,9 +929,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in // Less asserts that the first element is less than the second // -// a.Less(1, 2) -// a.Less(float64(1), float64(2)) -// a.Less("a", "b") +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -860,10 +941,10 @@ func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interfac // LessOrEqual asserts that the first element is less than or equal to the second // -// a.LessOrEqual(1, 2) -// a.LessOrEqual(2, 2) -// a.LessOrEqual("a", "b") -// a.LessOrEqual("b", "b") +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -873,10 +954,10 @@ func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...i // LessOrEqualf asserts that the first element is less than or equal to the second // -// a.LessOrEqualf(1, 2, "error message %s", "formatted") -// a.LessOrEqualf(2, 2, "error message %s", "formatted") -// a.LessOrEqualf("a", "b", "error message %s", "formatted") -// a.LessOrEqualf("b", "b", "error message %s", "formatted") +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -886,9 +967,9 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar // Lessf asserts that the first element is less than the second // -// a.Lessf(1, 2, "error message %s", "formatted") -// a.Lessf(float64(1), float64(2), "error message %s", "formatted") -// a.Lessf("a", "b", "error message %s", "formatted") +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -898,8 +979,8 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i // Negative asserts that the specified element is negative // -// a.Negative(-1) -// a.Negative(-1.23) +// a.Negative(-1) +// a.Negative(-1.23) func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -909,8 +990,8 @@ func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { // Negativef asserts that the specified element is negative // -// a.Negativef(-1, "error message %s", "formatted") -// a.Negativef(-1.23, "error message %s", "formatted") +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -921,7 +1002,7 @@ func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -932,7 +1013,7 @@ func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick ti // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // -// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -942,7 +1023,7 @@ func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick t // Nil asserts that the specified object is nil. // -// a.Nil(err) +// a.Nil(err) func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -952,7 +1033,7 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { // Nilf asserts that the specified object is nil. // -// a.Nilf(err, "error message %s", "formatted") +// a.Nilf(err, "error message %s", "formatted") func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -980,10 +1061,10 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) // NoError asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -993,10 +1074,10 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { // NoErrorf asserts that a function returned no error (i.e. `nil`). // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1025,9 +1106,9 @@ func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContains("Hello World", "Earth") -// a.NotContains(["Hello", "World"], "Earth") -// a.NotContains({"Hello": "World"}, "Earth") +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1038,9 +1119,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // -// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") -// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") -// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1051,9 +1132,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1064,9 +1145,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1076,7 +1157,7 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface // NotEqual asserts that the specified values are NOT equal. // -// a.NotEqual(obj1, obj2) +// a.NotEqual(obj1, obj2) // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1089,7 +1170,7 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr // NotEqualValues asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValues(obj1, obj2) +// a.NotEqualValues(obj1, obj2) func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1099,7 +1180,7 @@ func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, ms // NotEqualValuesf asserts that two objects are not equal even when converted to the same type // -// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1109,7 +1190,7 @@ func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, m // NotEqualf asserts that the specified values are NOT equal. // -// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") // // Pointer variable equality is determined based on the equality of the // referenced values (as opposed to the memory addresses). @@ -1138,9 +1219,29 @@ func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...in NotErrorIsf(a.t, err, target, msg, args...) } +// NotImplements asserts that an object does not implement the specified interface. +// +// a.NotImplements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotImplements(a.t, interfaceObject, object, msgAndArgs...) +} + +// NotImplementsf asserts that an object does not implement the specified interface. +// +// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotImplementsf(a.t, interfaceObject, object, msg, args...) +} + // NotNil asserts that the specified object is not nil. // -// a.NotNil(err) +// a.NotNil(err) func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1150,7 +1251,7 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { // NotNilf asserts that the specified object is not nil. // -// a.NotNilf(err, "error message %s", "formatted") +// a.NotNilf(err, "error message %s", "formatted") func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1160,7 +1261,7 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{} // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanics(func(){ RemainCalm() }) +// a.NotPanics(func(){ RemainCalm() }) func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1170,7 +1271,7 @@ func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{} // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // -// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1180,8 +1281,8 @@ func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...inte // NotRegexp asserts that a specified regexp does not match a string. // -// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") -// a.NotRegexp("^start", "it's not starting") +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1191,8 +1292,8 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in // NotRegexpf asserts that a specified regexp does not match a string. // -// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") -// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1202,7 +1303,7 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg // NotSame asserts that two pointers do not reference the same object. // -// a.NotSame(ptr1, ptr2) +// a.NotSame(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1215,7 +1316,7 @@ func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArg // NotSamef asserts that two pointers do not reference the same object. // -// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1226,10 +1327,12 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri NotSamef(a.t, expected, actual, msg, args...) } -// NotSubset asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubset asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +// a.NotSubset([1, 3, 4], [1, 2]) +// a.NotSubset({"x": 1, "y": 2}, {"z": 3}) func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1237,10 +1340,12 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs NotSubset(a.t, list, subset, msgAndArgs...) } -// NotSubsetf asserts that the specified list(array, slice...) contains not all -// elements given in the specified subset(array, slice...). +// NotSubsetf asserts that the specified list(array, slice...) or map does NOT +// contain all elements given in the specified subset list(array, slice...) or +// map. // -// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted") +// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted") func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1266,7 +1371,7 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { // Panics asserts that the code inside the specified PanicTestFunc panics. // -// a.Panics(func(){ GoCrazy() }) +// a.Panics(func(){ GoCrazy() }) func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1278,7 +1383,7 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1290,7 +1395,7 @@ func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, m // panics, and that the recovered panic value is an error that satisfies the // EqualError comparison. // -// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1301,7 +1406,7 @@ func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1312,7 +1417,7 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFun // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // -// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1322,7 +1427,7 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFu // Panicsf asserts that the code inside the specified PanicTestFunc panics. // -// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1332,8 +1437,8 @@ func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interfa // Positive asserts that the specified element is positive // -// a.Positive(1) -// a.Positive(1.23) +// a.Positive(1) +// a.Positive(1.23) func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1343,8 +1448,8 @@ func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { // Positivef asserts that the specified element is positive // -// a.Positivef(1, "error message %s", "formatted") -// a.Positivef(1.23, "error message %s", "formatted") +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1354,8 +1459,8 @@ func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { // Regexp asserts that a specified regexp matches a string. // -// a.Regexp(regexp.MustCompile("start"), "it's starting") -// a.Regexp("start...$", "it's not starting") +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1365,8 +1470,8 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter // Regexpf asserts that a specified regexp matches a string. // -// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") -// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1376,7 +1481,7 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args . // Same asserts that two pointers reference the same object. // -// a.Same(ptr1, ptr2) +// a.Same(ptr1, ptr2) // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1389,7 +1494,7 @@ func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs . // Samef asserts that two pointers reference the same object. // -// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// a.Samef(ptr1, ptr2, "error message %s", "formatted") // // Both arguments must be pointer variables. Pointer variable sameness is // determined based on the equality of both type and value. @@ -1400,10 +1505,11 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, Samef(a.t, expected, actual, msg, args...) } -// Subset asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subset asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +// a.Subset([1, 2, 3], [1, 2]) +// a.Subset({"x": 1, "y": 2}, {"x": 1}) func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1411,10 +1517,11 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ... Subset(a.t, list, subset, msgAndArgs...) } -// Subsetf asserts that the specified list(array, slice...) contains all -// elements given in the specified subset(array, slice...). +// Subsetf asserts that the specified list(array, slice...) or map contains all +// elements given in the specified subset list(array, slice...) or map. // -// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted") +// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted") func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1424,7 +1531,7 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a // True asserts that the specified value is true. // -// a.True(myBool) +// a.True(myBool) func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1434,7 +1541,7 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { // Truef asserts that the specified value is true. // -// a.Truef(myBool, "error message %s", "formatted") +// a.Truef(myBool, "error message %s", "formatted") func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1444,7 +1551,7 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { // WithinDuration asserts that the two times are within duration delta of each other. // -// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1454,7 +1561,7 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta // WithinDurationf asserts that the two times are within duration delta of each other. // -// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1464,7 +1571,7 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta // WithinRange asserts that a time is within a time range (inclusive). // -// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1474,7 +1581,7 @@ func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Tim // WithinRangef asserts that a time is within a time range (inclusive). // -// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/suite/doc.go b/vendor/github.com/stretchr/testify/suite/doc.go index f91a245d3..8d55a3aa8 100644 --- a/vendor/github.com/stretchr/testify/suite/doc.go +++ b/vendor/github.com/stretchr/testify/suite/doc.go @@ -29,37 +29,38 @@ // Suite object has assertion methods. // // A crude example: -// // Basic imports -// import ( -// "testing" -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/suite" -// ) // -// // Define the suite, and absorb the built-in basic suite -// // functionality from testify - including a T() method which -// // returns the current testing context -// type ExampleTestSuite struct { -// suite.Suite -// VariableThatShouldStartAtFive int -// } +// // Basic imports +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/suite" +// ) // -// // Make sure that VariableThatShouldStartAtFive is set to five -// // before each test -// func (suite *ExampleTestSuite) SetupTest() { -// suite.VariableThatShouldStartAtFive = 5 -// } +// // Define the suite, and absorb the built-in basic suite +// // functionality from testify - including a T() method which +// // returns the current testing context +// type ExampleTestSuite struct { +// suite.Suite +// VariableThatShouldStartAtFive int +// } // -// // All methods that begin with "Test" are run as tests within a -// // suite. -// func (suite *ExampleTestSuite) TestExample() { -// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) -// suite.Equal(5, suite.VariableThatShouldStartAtFive) -// } +// // Make sure that VariableThatShouldStartAtFive is set to five +// // before each test +// func (suite *ExampleTestSuite) SetupTest() { +// suite.VariableThatShouldStartAtFive = 5 +// } // -// // In order for 'go test' to run this suite, we need to create -// // a normal test function and pass our suite to suite.Run -// func TestExampleTestSuite(t *testing.T) { -// suite.Run(t, new(ExampleTestSuite)) -// } +// // All methods that begin with "Test" are run as tests within a +// // suite. +// func (suite *ExampleTestSuite) TestExample() { +// assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) +// suite.Equal(5, suite.VariableThatShouldStartAtFive) +// } +// +// // In order for 'go test' to run this suite, we need to create +// // a normal test function and pass our suite to suite.Run +// func TestExampleTestSuite(t *testing.T) { +// suite.Run(t, new(ExampleTestSuite)) +// } package suite diff --git a/vendor/github.com/stretchr/testify/suite/suite.go b/vendor/github.com/stretchr/testify/suite/suite.go index 8b4202d89..18443a91c 100644 --- a/vendor/github.com/stretchr/testify/suite/suite.go +++ b/vendor/github.com/stretchr/testify/suite/suite.go @@ -58,7 +58,7 @@ func (suite *Suite) Require() *require.Assertions { suite.mu.Lock() defer suite.mu.Unlock() if suite.require == nil { - suite.require = require.New(suite.T()) + panic("'Require' must not be called before 'Run' or 'SetT'") } return suite.require } @@ -72,17 +72,19 @@ func (suite *Suite) Assert() *assert.Assertions { suite.mu.Lock() defer suite.mu.Unlock() if suite.Assertions == nil { - suite.Assertions = assert.New(suite.T()) + panic("'Assert' must not be called before 'Run' or 'SetT'") } return suite.Assertions } func recoverAndFailOnPanic(t *testing.T) { + t.Helper() r := recover() failOnPanic(t, r) } func failOnPanic(t *testing.T, r interface{}) { + t.Helper() if r != nil { t.Errorf("test panicked: %v\n%s", r, debug.Stack()) t.FailNow() @@ -96,19 +98,20 @@ func failOnPanic(t *testing.T, r interface{}) { func (suite *Suite) Run(name string, subtest func()) bool { oldT := suite.T() - if setupSubTest, ok := suite.s.(SetupSubTest); ok { - setupSubTest.SetupSubTest() - } + return oldT.Run(name, func(t *testing.T) { + suite.SetT(t) + defer suite.SetT(oldT) + + defer recoverAndFailOnPanic(t) + + if setupSubTest, ok := suite.s.(SetupSubTest); ok { + setupSubTest.SetupSubTest() + } - defer func() { - suite.SetT(oldT) if tearDownSubTest, ok := suite.s.(TearDownSubTest); ok { - tearDownSubTest.TearDownSubTest() + defer tearDownSubTest.TearDownSubTest() } - }() - return oldT.Run(name, func(t *testing.T) { - suite.SetT(t) subtest() }) } @@ -164,6 +167,8 @@ func Run(t *testing.T, suite TestingSuite) { suite.SetT(t) defer recoverAndFailOnPanic(t) defer func() { + t.Helper() + r := recover() if stats != nil { diff --git a/vendor/modules.txt b/vendor/modules.txt index 5d8815e92..b21ed47c5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -689,11 +689,11 @@ github.com/ssgreg/nlreturn/v2/pkg/nlreturn # github.com/stbenjam/no-sprintf-host-port v0.1.1 ## explicit; go 1.16 github.com/stbenjam/no-sprintf-host-port/pkg/analyzer -# github.com/stretchr/objx v0.5.0 -## explicit; go 1.12 +# github.com/stretchr/objx v0.5.2 +## explicit; go 1.20 github.com/stretchr/objx -# github.com/stretchr/testify v1.8.2 -## explicit; go 1.13 +# github.com/stretchr/testify v1.9.0 +## explicit; go 1.17 github.com/stretchr/testify/assert github.com/stretchr/testify/mock github.com/stretchr/testify/require From 3562d4f3eb29355a50e3da7a1bc0e5e3209499c2 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:39:09 +0200 Subject: [PATCH 24/31] gomod: Update github.com/zenazn/goji --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/zenazn/goji/LICENSE | 2 +- .../zenazn/goji/web/mutil/writer_proxy.go | 34 ++++- .../goji/web/mutil/writer_proxy_go1_8.go | 136 ++++++++++++++++++ vendor/modules.txt | 2 +- 6 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 vendor/github.com/zenazn/goji/web/mutil/writer_proxy_go1_8.go diff --git a/go.mod b/go.mod index 6bfacc70b..bb17db434 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/uber/jaeger-client-go v2.14.0+incompatible github.com/uber/jaeger-lib v1.5.0 - github.com/zenazn/goji v0.9.0 + github.com/zenazn/goji v1.0.1 golang.org/x/text v0.14.0 golang.org/x/tools/cmd/cover v0.1.0-deprecated golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e diff --git a/go.sum b/go.sum index 110bdeed3..305ac33ad 100644 --- a/go.sum +++ b/go.sum @@ -683,8 +683,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= +github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= gitlab.com/bosi/decorder v0.2.3 h1:gX4/RgK16ijY8V+BRQHAySfQAb354T7/xQpDB2n10P0= gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE= gitlab.com/flimzy/testy v0.0.3/go.mod h1:YObF4cq711ubd/3U0ydRQQVz7Cnq/ChgJpVwNr/AJac= diff --git a/vendor/github.com/zenazn/goji/LICENSE b/vendor/github.com/zenazn/goji/LICENSE index 128f3fc63..446aba064 100644 --- a/vendor/github.com/zenazn/goji/LICENSE +++ b/vendor/github.com/zenazn/goji/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014, 2015 Carl Jackson (carl@avtok.com) +Copyright (c) 2014, 2015, 2016 Carl Jackson (carl@avtok.com) MIT License diff --git a/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go b/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go index d57281268..fb4a08bee 100644 --- a/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go +++ b/vendor/github.com/zenazn/goji/web/mutil/writer_proxy.go @@ -1,3 +1,5 @@ +// +build !go1.8 + package mutil import ( @@ -39,6 +41,9 @@ func WrapWriter(w http.ResponseWriter) WriterProxy { if cn && fl && hj && rf { return &fancyWriter{bw} } + if fl { + return &flushWriter{bw} + } return &bw } @@ -59,6 +64,7 @@ func (b *basicWriter) WriteHeader(code int) { b.ResponseWriter.WriteHeader(code) } } + func (b *basicWriter) Write(buf []byte) (int, error) { b.WriteHeader(http.StatusOK) n, err := b.ResponseWriter.Write(buf) @@ -72,20 +78,25 @@ func (b *basicWriter) Write(buf []byte) (int, error) { b.bytes += n return n, err } + func (b *basicWriter) maybeWriteHeader() { if !b.wroteHeader { b.WriteHeader(http.StatusOK) } } + func (b *basicWriter) Status() int { return b.code } + func (b *basicWriter) BytesWritten() int { return b.bytes } + func (b *basicWriter) Tee(w io.Writer) { b.tee = w } + func (b *basicWriter) Unwrap() http.ResponseWriter { return b.ResponseWriter } @@ -102,14 +113,17 @@ func (f *fancyWriter) CloseNotify() <-chan bool { cn := f.basicWriter.ResponseWriter.(http.CloseNotifier) return cn.CloseNotify() } + func (f *fancyWriter) Flush() { fl := f.basicWriter.ResponseWriter.(http.Flusher) fl.Flush() } + func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { hj := f.basicWriter.ResponseWriter.(http.Hijacker) return hj.Hijack() } + func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) { if f.basicWriter.tee != nil { return io.Copy(&f.basicWriter, r) @@ -119,7 +133,19 @@ func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) { return rf.ReadFrom(r) } -var _ http.CloseNotifier = &fancyWriter{} -var _ http.Flusher = &fancyWriter{} -var _ http.Hijacker = &fancyWriter{} -var _ io.ReaderFrom = &fancyWriter{} +type flushWriter struct { + basicWriter +} + +func (f *flushWriter) Flush() { + fl := f.basicWriter.ResponseWriter.(http.Flusher) + fl.Flush() +} + +var ( + _ http.CloseNotifier = &fancyWriter{} + _ http.Flusher = &fancyWriter{} + _ http.Hijacker = &fancyWriter{} + _ io.ReaderFrom = &fancyWriter{} + _ http.Flusher = &flushWriter{} +) diff --git a/vendor/github.com/zenazn/goji/web/mutil/writer_proxy_go1_8.go b/vendor/github.com/zenazn/goji/web/mutil/writer_proxy_go1_8.go new file mode 100644 index 000000000..2019c980e --- /dev/null +++ b/vendor/github.com/zenazn/goji/web/mutil/writer_proxy_go1_8.go @@ -0,0 +1,136 @@ +// +build go1.8 + +package mutil + +import ( + "bufio" + "io" + "net" + "net/http" +) + +// WriterProxy is a proxy around an http.ResponseWriter that allows you to hook +// into various parts of the response process. +type WriterProxy interface { + http.ResponseWriter + // Status returns the HTTP status of the request, or 0 if one has not + // yet been sent. + Status() int + // BytesWritten returns the total number of bytes sent to the client. + BytesWritten() int + // Tee causes the response body to be written to the given io.Writer in + // addition to proxying the writes through. Only one io.Writer can be + // tee'd to at once: setting a second one will overwrite the first. + // Writes will be sent to the proxy before being written to this + // io.Writer. It is illegal for the tee'd writer to be modified + // concurrently with writes. + Tee(io.Writer) + // Unwrap returns the original proxied target. + Unwrap() http.ResponseWriter +} + +// WrapWriter wraps an http.ResponseWriter, returning a proxy that allows you to +// hook into various parts of the response process. +func WrapWriter(w http.ResponseWriter) WriterProxy { + _, fl := w.(http.Flusher) + _, hj := w.(http.Hijacker) + _, rf := w.(io.ReaderFrom) + + bw := basicWriter{ResponseWriter: w} + if fl && hj && rf { + return &fancyWriter{bw} + } + return &bw +} + +// basicWriter wraps a http.ResponseWriter that implements the minimal +// http.ResponseWriter interface. +type basicWriter struct { + http.ResponseWriter + wroteHeader bool + code int + bytes int + tee io.Writer +} + +func (b *basicWriter) WriteHeader(code int) { + if !b.wroteHeader { + b.code = code + b.wroteHeader = true + b.ResponseWriter.WriteHeader(code) + } +} + +func (b *basicWriter) Write(buf []byte) (int, error) { + b.WriteHeader(http.StatusOK) + n, err := b.ResponseWriter.Write(buf) + if b.tee != nil { + _, err2 := b.tee.Write(buf[:n]) + // Prefer errors generated by the proxied writer. + if err == nil { + err = err2 + } + } + b.bytes += n + return n, err +} + +func (b *basicWriter) maybeWriteHeader() { + if !b.wroteHeader { + b.WriteHeader(http.StatusOK) + } +} + +func (b *basicWriter) Status() int { + return b.code +} + +func (b *basicWriter) BytesWritten() int { + return b.bytes +} + +func (b *basicWriter) Tee(w io.Writer) { + b.tee = w +} + +func (b *basicWriter) Unwrap() http.ResponseWriter { + return b.ResponseWriter +} + +// fancyWriter is a writer that additionally satisfies http.Pusher, +// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case +// of wrapping the http.ResponseWriter that package http gives you, in order to +// make the proxied object support the full method set of the proxied object. +type fancyWriter struct { + basicWriter +} + +func (f *fancyWriter) Push(target string, opts *http.PushOptions) error { + return f.basicWriter.ResponseWriter.(http.Pusher).Push(target, opts) +} + +func (f *fancyWriter) Flush() { + fl := f.basicWriter.ResponseWriter.(http.Flusher) + fl.Flush() +} + +func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hj := f.basicWriter.ResponseWriter.(http.Hijacker) + return hj.Hijack() +} + +func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) { + if f.basicWriter.tee != nil { + return io.Copy(&f.basicWriter, r) + } + rf := f.basicWriter.ResponseWriter.(io.ReaderFrom) + f.basicWriter.maybeWriteHeader() + return rf.ReadFrom(r) +} + +var ( + _ http.Pusher = &fancyWriter{} + _ http.Flusher = &fancyWriter{} + _ http.Hijacker = &fancyWriter{} + _ io.ReaderFrom = &fancyWriter{} +) diff --git a/vendor/modules.txt b/vendor/modules.txt index b21ed47c5..5d2c21b56 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -771,7 +771,7 @@ github.com/yagipy/maintidx/pkg/halstvol # github.com/yeya24/promlinter v0.2.0 ## explicit; go 1.16 github.com/yeya24/promlinter -# github.com/zenazn/goji v0.9.0 +# github.com/zenazn/goji v1.0.1 ## explicit github.com/zenazn/goji/web/mutil # gitlab.com/bosi/decorder v0.2.3 From d2cdf6bd4483c30ad583d4f358ded56a3782fe9b Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:40:35 +0200 Subject: [PATCH 25/31] gomod: Remove golang.org/x/tools/cmd/cover (deprecated) --- go.mod | 1 - go.sum | 2 - vendor/golang.org/x/tools/cmd/cover/LICENSE | 27 - vendor/golang.org/x/tools/cmd/cover/README.md | 3 - vendor/golang.org/x/tools/cmd/cover/cover.go | 721 ------------------ vendor/golang.org/x/tools/cmd/cover/doc.go | 25 - vendor/golang.org/x/tools/cmd/cover/func.go | 166 ---- vendor/golang.org/x/tools/cmd/cover/html.go | 284 ------- vendor/modules.txt | 3 - 9 files changed, 1232 deletions(-) delete mode 100644 vendor/golang.org/x/tools/cmd/cover/LICENSE delete mode 100644 vendor/golang.org/x/tools/cmd/cover/README.md delete mode 100644 vendor/golang.org/x/tools/cmd/cover/cover.go delete mode 100644 vendor/golang.org/x/tools/cmd/cover/doc.go delete mode 100644 vendor/golang.org/x/tools/cmd/cover/func.go delete mode 100644 vendor/golang.org/x/tools/cmd/cover/html.go diff --git a/go.mod b/go.mod index bb17db434..39943319f 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/uber/jaeger-lib v1.5.0 github.com/zenazn/goji v1.0.1 golang.org/x/text v0.14.0 - golang.org/x/tools/cmd/cover v0.1.0-deprecated golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e google.golang.org/grpc v1.60.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 diff --git a/go.sum b/go.sum index 305ac33ad..005ae5f4b 100644 --- a/go.sum +++ b/go.sum @@ -1022,8 +1022,6 @@ golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/tools/cmd/cover v0.1.0-deprecated h1:Rwy+mWYz6loAF+LnG1jHG/JWMHRMMC2/1XX3Ejkx9lA= -golang.org/x/tools/cmd/cover v0.1.0-deprecated/go.mod h1:hMDiIvlpN1NoVgmjLjUJE9tMHyxHjFX7RuQ+rW12mSA= golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e h1:5Hq/b1GYIt4/LvB6c4KOX+XyV1iOEjrP8uigwK7EQpU= golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e/go.mod h1:7tDfEDtOLlzHQRi4Yzfg5seVBSvouUIjyPzBx4q5CxQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/golang.org/x/tools/cmd/cover/LICENSE b/vendor/golang.org/x/tools/cmd/cover/LICENSE deleted file mode 100644 index 6a66aea5e..000000000 --- a/vendor/golang.org/x/tools/cmd/cover/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 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. diff --git a/vendor/golang.org/x/tools/cmd/cover/README.md b/vendor/golang.org/x/tools/cmd/cover/README.md deleted file mode 100644 index 62e60279a..000000000 --- a/vendor/golang.org/x/tools/cmd/cover/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Deprecated - -NOTE: For Go releases 1.5 and later, this tool lives in the standard repository. The code here is not maintained. diff --git a/vendor/golang.org/x/tools/cmd/cover/cover.go b/vendor/golang.org/x/tools/cmd/cover/cover.go deleted file mode 100644 index 0c7db1025..000000000 --- a/vendor/golang.org/x/tools/cmd/cover/cover.go +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "bytes" - "flag" - "fmt" - "go/ast" - "go/parser" - "go/printer" - "go/token" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "sort" - "strconv" - "strings" -) - -const usageMessage = "" + - `Usage of 'go tool cover': -Given a coverage profile produced by 'go test': - go test -coverprofile=c.out - -Open a web browser displaying annotated source code: - go tool cover -html=c.out - -Write out an HTML file instead of launching a web browser: - go tool cover -html=c.out -o coverage.html - -Display coverage percentages to stdout for each function: - go tool cover -func=c.out - -Finally, to generate modified source code with coverage annotations -(what go test -cover does): - go tool cover -mode=set -var=CoverageVariableName program.go -` - -func usage() { - fmt.Fprint(os.Stderr, usageMessage) - fmt.Fprintln(os.Stderr, "\nFlags:") - flag.PrintDefaults() - fmt.Fprintln(os.Stderr, "\n Only one of -html, -func, or -mode may be set.") - os.Exit(2) -} - -var ( - mode = flag.String("mode", "", "coverage mode: set, count, atomic") - varVar = flag.String("var", "GoCover", "name of coverage variable to generate") - output = flag.String("o", "", "file for output; default: stdout") - htmlOut = flag.String("html", "", "generate HTML representation of coverage profile") - funcOut = flag.String("func", "", "output coverage profile information for each function") -) - -var profile string // The profile to read; the value of -html or -func - -var counterStmt func(*File, ast.Expr) ast.Stmt - -const ( - atomicPackagePath = "sync/atomic" - atomicPackageName = "_cover_atomic_" -) - -func main() { - flag.Usage = usage - flag.Parse() - - // Usage information when no arguments. - if flag.NFlag() == 0 && flag.NArg() == 0 { - flag.Usage() - } - - err := parseFlags() - if err != nil { - fmt.Fprintln(os.Stderr, err) - fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`) - os.Exit(2) - } - - // Generate coverage-annotated source. - if *mode != "" { - annotate(flag.Arg(0)) - return - } - - // Output HTML or function coverage information. - if *htmlOut != "" { - err = htmlOutput(profile, *output) - } else { - err = funcOutput(profile, *output) - } - - if err != nil { - fmt.Fprintf(os.Stderr, "cover: %v\n", err) - os.Exit(2) - } -} - -// parseFlags sets the profile and counterStmt globals and performs validations. -func parseFlags() error { - profile = *htmlOut - if *funcOut != "" { - if profile != "" { - return fmt.Errorf("too many options") - } - profile = *funcOut - } - - // Must either display a profile or rewrite Go source. - if (profile == "") == (*mode == "") { - return fmt.Errorf("too many options") - } - - if *mode != "" { - switch *mode { - case "set": - counterStmt = setCounterStmt - case "count": - counterStmt = incCounterStmt - case "atomic": - counterStmt = atomicCounterStmt - default: - return fmt.Errorf("unknown -mode %v", *mode) - } - - if flag.NArg() == 0 { - return fmt.Errorf("missing source file") - } else if flag.NArg() == 1 { - return nil - } - } else if flag.NArg() == 0 { - return nil - } - return fmt.Errorf("too many arguments") -} - -// Block represents the information about a basic block to be recorded in the analysis. -// Note: Our definition of basic block is based on control structures; we don't break -// apart && and ||. We could but it doesn't seem important enough to bother. -type Block struct { - startByte token.Pos - endByte token.Pos - numStmt int -} - -// File is a wrapper for the state of a file used in the parser. -// The basic parse tree walker is a method of this type. -type File struct { - fset *token.FileSet - name string // Name of file. - astFile *ast.File - blocks []Block - atomicPkg string // Package name for "sync/atomic" in this file. -} - -// Visit implements the ast.Visitor interface. -func (f *File) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.BlockStmt: - // If it's a switch or select, the body is a list of case clauses; don't tag the block itself. - if len(n.List) > 0 { - switch n.List[0].(type) { - case *ast.CaseClause: // switch - for _, n := range n.List { - clause := n.(*ast.CaseClause) - clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false) - } - return f - case *ast.CommClause: // select - for _, n := range n.List { - clause := n.(*ast.CommClause) - clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false) - } - return f - } - } - n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace. - case *ast.IfStmt: - ast.Walk(f, n.Body) - if n.Else == nil { - return nil - } - // The elses are special, because if we have - // if x { - // } else if y { - // } - // we want to cover the "if y". To do this, we need a place to drop the counter, - // so we add a hidden block: - // if x { - // } else { - // if y { - // } - // } - switch stmt := n.Else.(type) { - case *ast.IfStmt: - block := &ast.BlockStmt{ - Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else". - List: []ast.Stmt{stmt}, - Rbrace: stmt.End(), - } - n.Else = block - case *ast.BlockStmt: - stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else". - default: - panic("unexpected node type in if") - } - ast.Walk(f, n.Else) - return nil - case *ast.SelectStmt: - // Don't annotate an empty select - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - case *ast.SwitchStmt: - // Don't annotate an empty switch - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - case *ast.TypeSwitchStmt: - // Don't annotate an empty type switch - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - } - return f -} - -// unquote returns the unquoted string. -func unquote(s string) string { - t, err := strconv.Unquote(s) - if err != nil { - log.Fatalf("cover: improperly quoted string %q\n", s) - } - return t -} - -// addImport adds an import for the specified path, if one does not already exist, and returns -// the local package name. -func (f *File) addImport(path string) string { - // Does the package already import it? - for _, s := range f.astFile.Imports { - if unquote(s.Path.Value) == path { - if s.Name != nil { - return s.Name.Name - } - return filepath.Base(path) - } - } - newImport := &ast.ImportSpec{ - Name: ast.NewIdent(atomicPackageName), - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: fmt.Sprintf("%q", path), - }, - } - impDecl := &ast.GenDecl{ - Tok: token.IMPORT, - Specs: []ast.Spec{ - newImport, - }, - } - // Make the new import the first Decl in the file. - astFile := f.astFile - astFile.Decls = append(astFile.Decls, nil) - copy(astFile.Decls[1:], astFile.Decls[0:]) - astFile.Decls[0] = impDecl - astFile.Imports = append(astFile.Imports, newImport) - - // Now refer to the package, just in case it ends up unused. - // That is, append to the end of the file the declaration - // var _ = _cover_atomic_.AddUint32 - reference := &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{ - ast.NewIdent("_"), - }, - Values: []ast.Expr{ - &ast.SelectorExpr{ - X: ast.NewIdent(atomicPackageName), - Sel: ast.NewIdent("AddUint32"), - }, - }, - }, - }, - } - astFile.Decls = append(astFile.Decls, reference) - return atomicPackageName -} - -var slashslash = []byte("//") - -// initialComments returns the prefix of content containing only -// whitespace and line comments. Any +build directives must appear -// within this region. This approach is more reliable than using -// go/printer to print a modified AST containing comments. -func initialComments(content []byte) []byte { - // Derived from go/build.Context.shouldBuild. - end := 0 - p := content - for len(p) > 0 { - line := p - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, p = line[:i], p[i+1:] - } else { - p = p[len(p):] - } - line = bytes.TrimSpace(line) - if len(line) == 0 { // Blank line. - end = len(content) - len(p) - continue - } - if !bytes.HasPrefix(line, slashslash) { // Not comment line. - break - } - } - return content[:end] -} - -func annotate(name string) { - fset := token.NewFileSet() - content, err := ioutil.ReadFile(name) - if err != nil { - log.Fatalf("cover: %s: %s", name, err) - } - parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments) - if err != nil { - log.Fatalf("cover: %s: %s", name, err) - } - parsedFile.Comments = trimComments(parsedFile, fset) - - file := &File{ - fset: fset, - name: name, - astFile: parsedFile, - } - if *mode == "atomic" { - file.atomicPkg = file.addImport(atomicPackagePath) - } - ast.Walk(file, file.astFile) - fd := os.Stdout - if *output != "" { - var err error - fd, err = os.Create(*output) - if err != nil { - log.Fatalf("cover: %s", err) - } - } - fd.Write(initialComments(content)) // Retain '// +build' directives. - file.print(fd) - // After printing the source tree, add some declarations for the counters etc. - // We could do this by adding to the tree, but it's easier just to print the text. - file.addVariables(fd) -} - -// trimComments drops all but the //go: comments, some of which are semantically important. -// We drop all others because they can appear in places that cause our counters -// to appear in syntactically incorrect places. //go: appears at the beginning of -// the line and is syntactically safe. -func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup { - var comments []*ast.CommentGroup - for _, group := range file.Comments { - var list []*ast.Comment - for _, comment := range group.List { - if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 { - list = append(list, comment) - } - } - if list != nil { - comments = append(comments, &ast.CommentGroup{List: list}) - } - } - return comments -} - -func (f *File) print(w io.Writer) { - printer.Fprint(w, f.fset, f.astFile) -} - -// intLiteral returns an ast.BasicLit representing the integer value. -func (f *File) intLiteral(i int) *ast.BasicLit { - node := &ast.BasicLit{ - Kind: token.INT, - Value: fmt.Sprint(i), - } - return node -} - -// index returns an ast.BasicLit representing the number of counters present. -func (f *File) index() *ast.BasicLit { - return f.intLiteral(len(f.blocks)) -} - -// setCounterStmt returns the expression: __count[23] = 1. -func setCounterStmt(f *File, counter ast.Expr) ast.Stmt { - return &ast.AssignStmt{ - Lhs: []ast.Expr{counter}, - Tok: token.ASSIGN, - Rhs: []ast.Expr{f.intLiteral(1)}, - } -} - -// incCounterStmt returns the expression: __count[23]++. -func incCounterStmt(f *File, counter ast.Expr) ast.Stmt { - return &ast.IncDecStmt{ - X: counter, - Tok: token.INC, - } -} - -// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1) -func atomicCounterStmt(f *File, counter ast.Expr) ast.Stmt { - return &ast.ExprStmt{ - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: ast.NewIdent(f.atomicPkg), - Sel: ast.NewIdent("AddUint32"), - }, - Args: []ast.Expr{&ast.UnaryExpr{ - Op: token.AND, - X: counter, - }, - f.intLiteral(1), - }, - }, - } -} - -// newCounter creates a new counter expression of the appropriate form. -func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt { - counter := &ast.IndexExpr{ - X: &ast.SelectorExpr{ - X: ast.NewIdent(*varVar), - Sel: ast.NewIdent("Count"), - }, - Index: f.index(), - } - stmt := counterStmt(f, counter) - f.blocks = append(f.blocks, Block{start, end, numStmt}) - return stmt -} - -// addCounters takes a list of statements and adds counters to the beginning of -// each basic block at the top level of that list. For instance, given -// -// S1 -// if cond { -// S2 -// } -// S3 -// -// counters will be added before S1 and before S3. The block containing S2 -// will be visited in a separate call. -// TODO: Nested simple blocks get unnecessary (but correct) counters -func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt { - // Special case: make sure we add a counter to an empty block. Can't do this below - // or we will add a counter to an empty statement list after, say, a return statement. - if len(list) == 0 { - return []ast.Stmt{f.newCounter(pos, blockEnd, 0)} - } - // We have a block (statement list), but it may have several basic blocks due to the - // appearance of statements that affect the flow of control. - var newList []ast.Stmt - for { - // Find first statement that affects flow of control (break, continue, if, etc.). - // It will be the last statement of this basic block. - var last int - end := blockEnd - for last = 0; last < len(list); last++ { - end = f.statementBoundary(list[last]) - if f.endsBasicSourceBlock(list[last]) { - extendToClosingBrace = false // Block is broken up now. - last++ - break - } - } - if extendToClosingBrace { - end = blockEnd - } - if pos != end { // Can have no source to cover if e.g. blocks abut. - newList = append(newList, f.newCounter(pos, end, last)) - } - newList = append(newList, list[0:last]...) - list = list[last:] - if len(list) == 0 { - break - } - pos = list[0].Pos() - } - return newList -} - -// hasFuncLiteral reports the existence and position of the first func literal -// in the node, if any. If a func literal appears, it usually marks the termination -// of a basic block because the function body is itself a block. -// Therefore we draw a line at the start of the body of the first function literal we find. -// TODO: what if there's more than one? Probably doesn't matter much. -func hasFuncLiteral(n ast.Node) (bool, token.Pos) { - if n == nil { - return false, 0 - } - var literal funcLitFinder - ast.Walk(&literal, n) - return literal.found(), token.Pos(literal) -} - -// statementBoundary finds the location in s that terminates the current basic -// block in the source. -func (f *File) statementBoundary(s ast.Stmt) token.Pos { - // Control flow statements are easy. - switch s := s.(type) { - case *ast.BlockStmt: - // Treat blocks like basic blocks to avoid overlapping counters. - return s.Lbrace - case *ast.IfStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Cond) - if found { - return pos - } - return s.Body.Lbrace - case *ast.ForStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Cond) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Post) - if found { - return pos - } - return s.Body.Lbrace - case *ast.LabeledStmt: - return f.statementBoundary(s.Stmt) - case *ast.RangeStmt: - found, pos := hasFuncLiteral(s.X) - if found { - return pos - } - return s.Body.Lbrace - case *ast.SwitchStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Tag) - if found { - return pos - } - return s.Body.Lbrace - case *ast.SelectStmt: - return s.Body.Lbrace - case *ast.TypeSwitchStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - return s.Body.Lbrace - } - // If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal. - // If it does, that's tricky because we want to exclude the body of the function from this block. - // Draw a line at the start of the body of the first function literal we find. - // TODO: what if there's more than one? Probably doesn't matter much. - found, pos := hasFuncLiteral(s) - if found { - return pos - } - return s.End() -} - -// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc., -// or if it's just problematic, for instance contains a function literal, which will complicate -// accounting due to the block-within-an expression. -func (f *File) endsBasicSourceBlock(s ast.Stmt) bool { - switch s := s.(type) { - case *ast.BlockStmt: - // Treat blocks like basic blocks to avoid overlapping counters. - return true - case *ast.BranchStmt: - return true - case *ast.ForStmt: - return true - case *ast.IfStmt: - return true - case *ast.LabeledStmt: - return f.endsBasicSourceBlock(s.Stmt) - case *ast.RangeStmt: - return true - case *ast.SwitchStmt: - return true - case *ast.SelectStmt: - return true - case *ast.TypeSwitchStmt: - return true - case *ast.ExprStmt: - // Calls to panic change the flow. - // We really should verify that "panic" is the predefined function, - // but without type checking we can't and the likelihood of it being - // an actual problem is vanishingly small. - if call, ok := s.X.(*ast.CallExpr); ok { - if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 { - return true - } - } - } - found, _ := hasFuncLiteral(s) - return found -} - -// funcLitFinder implements the ast.Visitor pattern to find the location of any -// function literal in a subtree. -type funcLitFinder token.Pos - -func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) { - if f.found() { - return nil // Prune search. - } - switch n := node.(type) { - case *ast.FuncLit: - *f = funcLitFinder(n.Body.Lbrace) - return nil // Prune search. - } - return f -} - -func (f *funcLitFinder) found() bool { - return token.Pos(*f) != token.NoPos -} - -// Sort interface for []block1; used for self-check in addVariables. - -type block1 struct { - Block - index int -} - -type blockSlice []block1 - -func (b blockSlice) Len() int { return len(b) } -func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte } -func (b blockSlice) Swap(i, j int) { b[i], b[j] = b[j], b[i] } - -// offset translates a token position into a 0-indexed byte offset. -func (f *File) offset(pos token.Pos) int { - return f.fset.Position(pos).Offset -} - -// addVariables adds to the end of the file the declarations to set up the counter and position variables. -func (f *File) addVariables(w io.Writer) { - // Self-check: Verify that the instrumented basic blocks are disjoint. - t := make([]block1, len(f.blocks)) - for i := range f.blocks { - t[i].Block = f.blocks[i] - t[i].index = i - } - sort.Sort(blockSlice(t)) - for i := 1; i < len(t); i++ { - if t[i-1].endByte > t[i].startByte { - fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index) - // Note: error message is in byte positions, not token positions. - fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n", - f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte), - f.name, f.offset(t[i].startByte), f.offset(t[i].endByte)) - } - } - - // Declare the coverage struct as a package-level variable. - fmt.Fprintf(w, "\nvar %s = struct {\n", *varVar) - fmt.Fprintf(w, "\tCount [%d]uint32\n", len(f.blocks)) - fmt.Fprintf(w, "\tPos [3 * %d]uint32\n", len(f.blocks)) - fmt.Fprintf(w, "\tNumStmt [%d]uint16\n", len(f.blocks)) - fmt.Fprintf(w, "} {\n") - - // Initialize the position array field. - fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks)) - - // A nice long list of positions. Each position is encoded as follows to reduce size: - // - 32-bit starting line number - // - 32-bit ending line number - // - (16 bit ending column number << 16) | (16-bit starting column number). - for i, block := range f.blocks { - start := f.fset.Position(block.startByte) - end := f.fset.Position(block.endByte) - fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i) - } - - // Close the position array. - fmt.Fprintf(w, "\t},\n") - - // Initialize the position array field. - fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks)) - - // A nice long list of statements-per-block, so we can give a conventional - // valuation of "percent covered". To save space, it's a 16-bit number, so we - // clamp it if it overflows - won't matter in practice. - for i, block := range f.blocks { - n := block.numStmt - if n > 1<<16-1 { - n = 1<<16 - 1 - } - fmt.Fprintf(w, "\t\t%d, // %d\n", n, i) - } - - // Close the statements-per-block array. - fmt.Fprintf(w, "\t},\n") - - // Close the struct initialization. - fmt.Fprintf(w, "}\n") -} diff --git a/vendor/golang.org/x/tools/cmd/cover/doc.go b/vendor/golang.org/x/tools/cmd/cover/doc.go deleted file mode 100644 index 77dce442f..000000000 --- a/vendor/golang.org/x/tools/cmd/cover/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -/* -Cover is a program for analyzing the coverage profiles generated by -'go test -coverprofile=cover.out'. - -Deprecated: For Go releases 1.5 and later, this tool lives in the -standard repository. The code here is not maintained. - -Cover is also used by 'go test -cover' to rewrite the source code with -annotations to track which parts of each function are executed. -It operates on one Go source file at a time, computing approximate -basic block information by studying the source. It is thus more portable -than binary-rewriting coverage tools, but also a little less capable. -For instance, it does not probe inside && and || expressions, and can -be mildly confused by single statements with multiple function literals. - -For usage information, please see: - - go help testflag - go tool cover -help -*/ -package main // import "golang.org/x/tools/cmd/cover" diff --git a/vendor/golang.org/x/tools/cmd/cover/func.go b/vendor/golang.org/x/tools/cmd/cover/func.go deleted file mode 100644 index 41d9fceca..000000000 --- a/vendor/golang.org/x/tools/cmd/cover/func.go +++ /dev/null @@ -1,166 +0,0 @@ -// 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. - -// This file implements the visitor that computes the (line, column)-(line-column) range for each function. - -package main - -import ( - "bufio" - "fmt" - "go/ast" - "go/build" - "go/parser" - "go/token" - "os" - "path/filepath" - "text/tabwriter" - - "golang.org/x/tools/cover" -) - -// funcOutput takes two file names as arguments, a coverage profile to read as input and an output -// file to write ("" means to write to standard output). The function reads the profile and produces -// as output the coverage data broken down by function, like this: -// -// fmt/format.go:30: init 100.0% -// fmt/format.go:57: clearflags 100.0% -// ... -// fmt/scan.go:1046: doScan 100.0% -// fmt/scan.go:1075: advance 96.2% -// fmt/scan.go:1119: doScanf 96.8% -// total: (statements) 91.9% - -func funcOutput(profile, outputFile string) error { - profiles, err := cover.ParseProfiles(profile) - if err != nil { - return err - } - - var out *bufio.Writer - if outputFile == "" { - out = bufio.NewWriter(os.Stdout) - } else { - fd, err := os.Create(outputFile) - if err != nil { - return err - } - defer fd.Close() - out = bufio.NewWriter(fd) - } - defer out.Flush() - - tabber := tabwriter.NewWriter(out, 1, 8, 1, '\t', 0) - defer tabber.Flush() - - var total, covered int64 - for _, profile := range profiles { - fn := profile.FileName - file, err := findFile(fn) - if err != nil { - return err - } - funcs, err := findFuncs(file) - if err != nil { - return err - } - // Now match up functions and profile blocks. - for _, f := range funcs { - c, t := f.coverage(profile) - fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t)) - total += t - covered += c - } - } - fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total)) - - return nil -} - -// findFuncs parses the file and returns a slice of FuncExtent descriptors. -func findFuncs(name string) ([]*FuncExtent, error) { - fset := token.NewFileSet() - parsedFile, err := parser.ParseFile(fset, name, nil, 0) - if err != nil { - return nil, err - } - visitor := &FuncVisitor{ - fset: fset, - name: name, - astFile: parsedFile, - } - ast.Walk(visitor, visitor.astFile) - return visitor.funcs, nil -} - -// FuncExtent describes a function's extent in the source by file and position. -type FuncExtent struct { - name string - startLine int - startCol int - endLine int - endCol int -} - -// FuncVisitor implements the visitor that builds the function position list for a file. -type FuncVisitor struct { - fset *token.FileSet - name string // Name of file. - astFile *ast.File - funcs []*FuncExtent -} - -// Visit implements the ast.Visitor interface. -func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.FuncDecl: - start := v.fset.Position(n.Pos()) - end := v.fset.Position(n.End()) - fe := &FuncExtent{ - name: n.Name.Name, - startLine: start.Line, - startCol: start.Column, - endLine: end.Line, - endCol: end.Column, - } - v.funcs = append(v.funcs, fe) - } - return v -} - -// coverage returns the fraction of the statements in the function that were covered, as a numerator and denominator. -func (f *FuncExtent) coverage(profile *cover.Profile) (num, den int64) { - // We could avoid making this n^2 overall by doing a single scan and annotating the functions, - // but the sizes of the data structures is never very large and the scan is almost instantaneous. - var covered, total int64 - // The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block. - for _, b := range profile.Blocks { - if b.StartLine > f.endLine || (b.StartLine == f.endLine && b.StartCol >= f.endCol) { - // Past the end of the function. - break - } - if b.EndLine < f.startLine || (b.EndLine == f.startLine && b.EndCol <= f.startCol) { - // Before the beginning of the function - continue - } - total += int64(b.NumStmt) - if b.Count > 0 { - covered += int64(b.NumStmt) - } - } - if total == 0 { - total = 1 // Avoid zero denominator. - } - return covered, total -} - -// findFile finds the location of the named file in GOROOT, GOPATH etc. -func findFile(file string) (string, error) { - dir, file := filepath.Split(file) - pkg, err := build.Import(dir, ".", build.FindOnly) - if err != nil { - return "", fmt.Errorf("can't find %q: %v", file, err) - } - return filepath.Join(pkg.Dir, file), nil -} diff --git a/vendor/golang.org/x/tools/cmd/cover/html.go b/vendor/golang.org/x/tools/cmd/cover/html.go deleted file mode 100644 index 0f8c72542..000000000 --- a/vendor/golang.org/x/tools/cmd/cover/html.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "bufio" - "bytes" - "fmt" - exec "golang.org/x/sys/execabs" - "html/template" - "io" - "io/ioutil" - "math" - "os" - "path/filepath" - "runtime" - - "golang.org/x/tools/cover" -) - -// htmlOutput reads the profile data from profile and generates an HTML -// coverage report, writing it to outfile. If outfile is empty, -// it writes the report to a temporary file and opens it in a web browser. -func htmlOutput(profile, outfile string) error { - profiles, err := cover.ParseProfiles(profile) - if err != nil { - return err - } - - var d templateData - - for _, profile := range profiles { - fn := profile.FileName - if profile.Mode == "set" { - d.Set = true - } - file, err := findFile(fn) - if err != nil { - return err - } - src, err := ioutil.ReadFile(file) - if err != nil { - return fmt.Errorf("can't read %q: %v", fn, err) - } - var buf bytes.Buffer - err = htmlGen(&buf, src, profile.Boundaries(src)) - if err != nil { - return err - } - d.Files = append(d.Files, &templateFile{ - Name: fn, - Body: template.HTML(buf.String()), - Coverage: percentCovered(profile), - }) - } - - var out *os.File - if outfile == "" { - var dir string - dir, err = ioutil.TempDir("", "cover") - if err != nil { - return err - } - out, err = os.Create(filepath.Join(dir, "coverage.html")) - } else { - out, err = os.Create(outfile) - } - if err != nil { - return err - } - err = htmlTemplate.Execute(out, d) - if err == nil { - err = out.Close() - } - if err != nil { - return err - } - - if outfile == "" { - if !startBrowser("file://" + out.Name()) { - fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name()) - } - } - - return nil -} - -// percentCovered returns, as a percentage, the fraction of the statements in -// the profile covered by the test run. -// In effect, it reports the coverage of a given source file. -func percentCovered(p *cover.Profile) float64 { - var total, covered int64 - for _, b := range p.Blocks { - total += int64(b.NumStmt) - if b.Count > 0 { - covered += int64(b.NumStmt) - } - } - if total == 0 { - return 0 - } - return float64(covered) / float64(total) * 100 -} - -// htmlGen generates an HTML coverage report with the provided filename, -// source code, and tokens, and writes it to the given Writer. -func htmlGen(w io.Writer, src []byte, boundaries []cover.Boundary) error { - dst := bufio.NewWriter(w) - for i := range src { - for len(boundaries) > 0 && boundaries[0].Offset == i { - b := boundaries[0] - if b.Start { - n := 0 - if b.Count > 0 { - n = int(math.Floor(b.Norm*9)) + 1 - } - fmt.Fprintf(dst, ``, n, b.Count) - } else { - dst.WriteString("") - } - boundaries = boundaries[1:] - } - switch b := src[i]; b { - case '>': - dst.WriteString(">") - case '<': - dst.WriteString("<") - case '&': - dst.WriteString("&") - case '\t': - dst.WriteString(" ") - default: - dst.WriteByte(b) - } - } - return dst.Flush() -} - -// startBrowser tries to open the URL in a browser -// and reports whether it succeeds. -func startBrowser(url string) bool { - // try to start the browser - var args []string - switch runtime.GOOS { - case "darwin": - args = []string{"open"} - case "windows": - args = []string{"cmd", "/c", "start"} - default: - args = []string{"xdg-open"} - } - cmd := exec.Command(args[0], append(args[1:], url)...) - return cmd.Start() == nil -} - -// rgb returns an rgb value for the specified coverage value -// between 0 (no coverage) and 10 (max coverage). -func rgb(n int) string { - if n == 0 { - return "rgb(192, 0, 0)" // Red - } - // Gradient from gray to green. - r := 128 - 12*(n-1) - g := 128 + 12*(n-1) - b := 128 + 3*(n-1) - return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b) -} - -// colors generates the CSS rules for coverage colors. -func colors() template.CSS { - var buf bytes.Buffer - for i := 0; i < 11; i++ { - fmt.Fprintf(&buf, ".cov%v { color: %v }\n", i, rgb(i)) - } - return template.CSS(buf.String()) -} - -var htmlTemplate = template.Must(template.New("html").Funcs(template.FuncMap{ - "colors": colors, -}).Parse(tmplHTML)) - -type templateData struct { - Files []*templateFile - Set bool -} - -type templateFile struct { - Name string - Body template.HTML - Coverage float64 -} - -const tmplHTML = ` - - - - - - - -
- -
- not tracked - {{if .Set}} - not covered - covered - {{else}} - no coverage - low coverage - * - * - * - * - * - * - * - * - high coverage - {{end}} -
-
-
- {{range $i, $f := .Files}} -
{{$f.Body}}
- {{end}} -
- - - -` diff --git a/vendor/modules.txt b/vendor/modules.txt index 5d2c21b56..da339510a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -919,9 +919,6 @@ golang.org/x/tools/internal/pkgbits golang.org/x/tools/internal/tokeninternal golang.org/x/tools/internal/typeparams golang.org/x/tools/internal/typesinternal -# golang.org/x/tools/cmd/cover v0.1.0-deprecated -## explicit; go 1.18 -golang.org/x/tools/cmd/cover # golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e ## explicit; go 1.18 golang.org/x/vuln/client From e5b12c9a3a35324e25a9e4d2d84e8bc3647bcd85 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:40:50 +0200 Subject: [PATCH 26/31] tools.go: Remove golang.org/x/tools/cmd/cover (deprecated) --- tools.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tools.go b/tools.go index 3ab3b445e..e08665405 100644 --- a/tools.go +++ b/tools.go @@ -6,7 +6,6 @@ package bricks import ( _ "github.com/golangci/golangci-lint/cmd/golangci-lint" _ "github.com/mattn/goveralls" - _ "golang.org/x/tools/cmd/cover" _ "golang.org/x/vuln/cmd/govulncheck" _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" _ "google.golang.org/protobuf/cmd/protoc-gen-go" From c9297d75c7424d91dfca1ad6ea227dc9d0259e07 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:41:35 +0200 Subject: [PATCH 27/31] gomod: Update golang.org/x/vuln --- go.mod | 10 +- go.sum | 23 +- vendor/golang.org/x/exp/maps/maps.go | 94 -- .../x/mod/internal/lazyregexp/lazyre.go | 2 +- vendor/golang.org/x/mod/modfile/print.go | 14 +- vendor/golang.org/x/mod/modfile/read.go | 2 +- vendor/golang.org/x/mod/modfile/rule.go | 156 ++- vendor/golang.org/x/mod/modfile/work.go | 65 +- vendor/golang.org/x/mod/module/module.go | 30 +- vendor/golang.org/x/mod/module/pseudo.go | 2 +- vendor/golang.org/x/mod/semver/semver.go | 6 +- vendor/golang.org/x/sync/errgroup/errgroup.go | 3 + vendor/golang.org/x/sync/errgroup/go120.go | 1 - .../golang.org/x/sync/errgroup/pre_go120.go | 1 - vendor/golang.org/x/sys/execabs/execabs.go | 102 -- .../golang.org/x/sys/execabs/execabs_go118.go | 17 - .../golang.org/x/sys/execabs/execabs_go119.go | 20 - .../x/tools/go/analysis/analysis.go | 12 +- .../x/tools/go/analysis/diagnostic.go | 22 +- vendor/golang.org/x/tools/go/analysis/doc.go | 2 +- .../tools/go/analysis/passes/assign/assign.go | 3 +- .../tools/go/analysis/passes/atomic/atomic.go | 20 +- .../passes/atomicalign/atomicalign.go | 36 +- .../x/tools/go/analysis/passes/bools/bools.go | 49 +- .../go/analysis/passes/buildssa/buildssa.go | 32 +- .../go/analysis/passes/buildtag/buildtag.go | 2 +- .../go/analysis/passes/cgocall/cgocall.go | 6 +- .../analysis/passes/cgocall/cgocall_go120.go | 13 + .../analysis/passes/cgocall/cgocall_go121.go | 13 + .../go/analysis/passes/composite/composite.go | 6 +- .../go/analysis/passes/copylock/copylock.go | 37 +- .../passes/deepequalerrors/deepequalerrors.go | 12 +- .../go/analysis/passes/errorsas/errorsas.go | 15 +- .../passes/httpresponse/httpresponse.go | 16 +- .../passes/ifaceassert/parameterized.go | 6 +- .../passes/internal/analysisutil/util.go | 62 +- .../go/analysis/passes/loopclosure/doc.go | 13 +- .../passes/loopclosure/loopclosure.go | 33 +- .../analysis/passes/lostcancel/lostcancel.go | 11 +- .../go/analysis/passes/nilfunc/nilfunc.go | 6 +- .../go/analysis/passes/nilness/nilness.go | 14 +- .../tools/go/analysis/passes/printf/printf.go | 11 +- .../tools/go/analysis/passes/printf/types.go | 2 +- .../reflectvaluecompare.go | 13 +- .../x/tools/go/analysis/passes/shift/shift.go | 2 +- .../passes/sigchanyzer/sigchanyzer.go | 4 + .../go/analysis/passes/sortslice/analyzer.go | 15 +- .../analysis/passes/stringintconv/string.go | 2 +- .../analysis/passes/testinggoroutine/doc.go | 2 +- .../testinggoroutine/testinggoroutine.go | 277 ++++-- .../analysis/passes/testinggoroutine/util.go | 96 ++ .../x/tools/go/analysis/passes/tests/tests.go | 13 +- .../analysis/passes/timeformat/timeformat.go | 33 +- .../go/analysis/passes/unmarshal/unmarshal.go | 10 +- .../tools/go/analysis/passes/unsafeptr/doc.go | 2 +- .../go/analysis/passes/unsafeptr/unsafeptr.go | 26 +- .../go/analysis/passes/unusedresult/doc.go | 8 +- .../passes/unusedresult/unusedresult.go | 100 +- .../x/tools/go/analysis/validate.go | 2 + .../x/tools/go/ast/astutil/enclosing.go | 8 +- .../x/tools/go/ast/astutil/rewrite.go | 8 +- .../x/tools/go/ast/inspector/inspector.go | 4 +- .../x/tools/go/ast/inspector/typeof.go | 4 +- .../x/tools/go/buildutil/fakecontext.go | 3 +- .../x/tools/go/buildutil/overlay.go | 3 +- .../x/tools/go/callgraph/callgraph.go | 1 + .../x/tools/go/callgraph/vta/graph.go | 24 +- .../go/callgraph/vta/internal/trie/builder.go | 4 +- .../x/tools/go/callgraph/vta/utils.go | 9 +- .../x/tools/go/callgraph/vta/vta.go | 3 + .../x/tools/go/gcexportdata/gcexportdata.go | 11 +- .../golang.org/x/tools/go/internal/cgo/cgo.go | 6 +- .../x/tools/go/internal/cgo/cgo_pkgconfig.go | 2 +- .../tools/go/internal/packagesdriver/sizes.go | 24 +- vendor/golang.org/x/tools/go/loader/loader.go | 5 +- vendor/golang.org/x/tools/go/packages/doc.go | 36 +- .../x/tools/go/packages/external.go | 2 +- .../golang.org/x/tools/go/packages/golist.go | 118 +-- .../x/tools/go/packages/golist_overlay.go | 492 ---------- .../x/tools/go/packages/packages.go | 197 ++-- vendor/golang.org/x/tools/go/ssa/builder.go | 920 ++++++++++-------- vendor/golang.org/x/tools/go/ssa/const.go | 2 +- vendor/golang.org/x/tools/go/ssa/coretype.go | 10 +- vendor/golang.org/x/tools/go/ssa/create.go | 178 ++-- vendor/golang.org/x/tools/go/ssa/doc.go | 42 +- vendor/golang.org/x/tools/go/ssa/emit.go | 89 +- vendor/golang.org/x/tools/go/ssa/func.go | 191 ++-- vendor/golang.org/x/tools/go/ssa/identical.go | 12 - .../golang.org/x/tools/go/ssa/identical_17.go | 12 - .../golang.org/x/tools/go/ssa/instantiate.go | 171 +--- vendor/golang.org/x/tools/go/ssa/lift.go | 20 +- vendor/golang.org/x/tools/go/ssa/lvalue.go | 4 +- vendor/golang.org/x/tools/go/ssa/methods.go | 393 ++++---- .../x/tools/go/ssa/parameterized.go | 56 +- vendor/golang.org/x/tools/go/ssa/print.go | 17 +- vendor/golang.org/x/tools/go/ssa/sanity.go | 11 +- vendor/golang.org/x/tools/go/ssa/source.go | 43 +- vendor/golang.org/x/tools/go/ssa/ssa.go | 177 ++-- .../golang.org/x/tools/go/ssa/ssautil/load.go | 65 +- .../x/tools/go/ssa/ssautil/visit.go | 143 ++- vendor/golang.org/x/tools/go/ssa/subst.go | 50 +- vendor/golang.org/x/tools/go/ssa/util.go | 99 +- vendor/golang.org/x/tools/go/ssa/wrappers.go | 211 ++-- .../x/tools/go/types/objectpath/objectpath.go | 162 ++- .../x/tools/go/types/typeutil/callee.go | 2 +- .../x/tools/go/types/typeutil/map.go | 20 +- vendor/golang.org/x/tools/imports/forward.go | 4 +- .../internal/analysisinternal/analysis.go | 386 ++++++++ .../analysisinternal}/extractdoc.go | 2 +- .../x/tools/internal/event/keys/util.go | 21 + .../x/tools/internal/event/tag/tag.go | 59 ++ .../x/tools/internal/fastwalk/fastwalk.go | 196 ---- .../internal/fastwalk/fastwalk_darwin.go | 119 --- .../fastwalk/fastwalk_dirent_fileno.go | 14 - .../internal/fastwalk/fastwalk_dirent_ino.go | 15 - .../fastwalk/fastwalk_dirent_namlen_bsd.go | 14 - .../fastwalk/fastwalk_dirent_namlen_linux.go | 29 - .../internal/fastwalk/fastwalk_portable.go | 38 - .../tools/internal/fastwalk/fastwalk_unix.go | 153 --- .../x/tools/internal/gcimporter/bexport.go | 852 ---------------- .../x/tools/internal/gcimporter/bimport.go | 907 +---------------- .../x/tools/internal/gcimporter/gcimporter.go | 18 +- .../x/tools/internal/gcimporter/iexport.go | 225 ++++- .../x/tools/internal/gcimporter/iimport.go | 236 +++-- .../tools/internal/gcimporter/ureader_yes.go | 9 + .../x/tools/internal/gocommand/invoke.go | 173 +++- .../x/tools/internal/gocommand/version.go | 18 +- .../x/tools/internal/gopathwalk/walk.go | 237 +++-- .../x/tools/internal/imports/fix.go | 103 +- .../x/tools/internal/imports/imports.go | 9 +- .../x/tools/internal/imports/mod.go | 17 +- .../x/tools/internal/imports/mod_cache.go | 2 +- .../x/tools/internal/imports/zstdlib.go | 230 +++++ .../internal/packagesinternal/packages.go | 8 - .../x/tools/internal/typeparams/common.go | 50 +- .../x/tools/internal/typeparams/coretype.go | 16 +- .../internal/typeparams/enabled_go117.go | 12 - .../internal/typeparams/enabled_go118.go | 15 - .../x/tools/internal/typeparams/normalize.go | 20 +- .../x/tools/internal/typeparams/termlist.go | 2 +- .../internal/typeparams/typeparams_go117.go | 197 ---- .../internal/typeparams/typeparams_go118.go | 151 --- .../x/tools/internal/typeparams/typeterm.go | 9 +- .../x/tools/internal/typesinternal/types.go | 9 - .../x/tools/internal/versions/gover.go | 172 ++++ .../x/tools/internal/versions/types.go | 19 + .../x/tools/internal/versions/types_go121.go | 20 + .../x/tools/internal/versions/types_go122.go | 24 + .../x/tools/internal/versions/versions.go | 52 + vendor/golang.org/x/vuln/client/cache.go | 30 - vendor/golang.org/x/vuln/client/client.go | 552 ----------- .../x/vuln/cmd/govulncheck/binary_118.go | 19 - .../x/vuln/cmd/govulncheck/binary_not118.go | 20 - .../golang.org/x/vuln/cmd/govulncheck/doc.go | 55 +- .../x/vuln/cmd/govulncheck/errors.go | 36 - .../x/vuln/cmd/govulncheck/formatting.go | 122 --- .../govulncheck/internal/govulncheck/cache.go | 142 --- .../internal/govulncheck/source.go | 112 --- .../govulncheck/internal/govulncheck/util.go | 120 --- .../golang.org/x/vuln/cmd/govulncheck/main.go | 432 +------- .../x/vuln/cmd/govulncheck/main_testmode.go | 13 - .../x/vuln/internal/buildinfo/README.md | 9 + .../internal/buildinfo/additions_buildinfo.go | 257 +++++ .../buildinfo/additions_scan.go} | 57 +- .../x/vuln/internal/buildinfo/buildinfo.go | 221 +++++ .../x/vuln/internal/client/client.go | 347 +++++++ .../x/vuln/internal/client/index.go | 120 +++ .../x/vuln/internal/client/schema.go | 77 ++ .../x/vuln/internal/client/source.go | 150 +++ .../x/vuln/internal/gosym/README.md | 11 + .../internal/gosym/additions.go | 61 +- .../{vulncheck => }/internal/gosym/pclntab.go | 22 +- .../{vulncheck => }/internal/gosym/symtab.go | 3 +- .../vuln/internal/govulncheck/govulncheck.go | 189 ++++ .../x/vuln/internal/govulncheck/handler.go | 59 ++ .../vuln/internal/govulncheck/jsonhandler.go | 44 + vendor/golang.org/x/vuln/internal/internal.go | 18 + vendor/golang.org/x/vuln/internal/osv/osv.go | 238 +++++ .../golang.org/x/vuln/internal/scan/binary.go | 103 ++ .../golang.org/x/vuln/internal/scan/color.go | 97 ++ .../golang.org/x/vuln/internal/scan/errors.go | 67 ++ .../x/vuln/internal/scan/extract.go | 63 ++ .../govulncheck => internal/scan}/filepath.go | 2 +- .../golang.org/x/vuln/internal/scan/flags.go | 197 ++++ .../golang.org/x/vuln/internal/scan/query.go | 74 ++ vendor/golang.org/x/vuln/internal/scan/run.go | 132 +++ .../golang.org/x/vuln/internal/scan/source.go | 124 +++ .../govulncheck => internal/scan}/stdlib.go | 11 +- .../x/vuln/internal/scan/template.go | 287 ++++++ .../golang.org/x/vuln/internal/scan/text.go | 481 +++++++++ .../golang.org/x/vuln/internal/scan/util.go | 59 ++ .../x/vuln/internal/semver/affects.go | 94 ++ .../x/vuln/internal/semver/fixed.go | 36 + .../x/vuln/internal/semver/semver.go | 18 +- .../x/vuln/internal/vulncheck/binary.go | 168 ++++ .../x/vuln/{ => internal}/vulncheck/doc.go | 4 +- .../x/vuln/internal/vulncheck/emit.go | 163 ++++ .../vuln/{ => internal}/vulncheck/entries.go | 6 + .../x/vuln/internal/vulncheck/fetch.go | 42 + .../x/vuln/internal/vulncheck/packages.go | 194 ++++ .../x/vuln/internal/vulncheck/slicing.go | 55 ++ .../x/vuln/internal/vulncheck/source.go | 308 ++++++ .../x/vuln/{ => internal}/vulncheck/utils.go | 177 ++-- .../x/vuln/internal/vulncheck/vulncheck.go | 312 ++++++ .../x/vuln/internal/vulncheck/witness.go | 447 +++++++++ vendor/golang.org/x/vuln/internal/web/url.go | 143 +++ vendor/golang.org/x/vuln/osv/json.go | 192 ---- vendor/golang.org/x/vuln/scan/scan.go | 106 ++ vendor/golang.org/x/vuln/vulncheck/binary.go | 149 --- vendor/golang.org/x/vuln/vulncheck/fetch.go | 88 -- .../x/vuln/vulncheck/internal/binscan/exe.go | 437 --------- .../x/vuln/vulncheck/internal/gosym/README.md | 4 - .../x/vuln/vulncheck/internal/gosym/sym.go | 40 - vendor/golang.org/x/vuln/vulncheck/lib.sh | 54 - vendor/golang.org/x/vuln/vulncheck/slicing.go | 54 - vendor/golang.org/x/vuln/vulncheck/source.go | 515 ---------- .../golang.org/x/vuln/vulncheck/vulncheck.go | 484 --------- vendor/golang.org/x/vuln/vulncheck/witness.go | 394 -------- vendor/modules.txt | 37 +- 219 files changed, 10282 insertions(+), 10205 deletions(-) delete mode 100644 vendor/golang.org/x/exp/maps/maps.go delete mode 100644 vendor/golang.org/x/sys/execabs/execabs.go delete mode 100644 vendor/golang.org/x/sys/execabs/execabs_go118.go delete mode 100644 vendor/golang.org/x/sys/execabs/execabs_go119.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go delete mode 100644 vendor/golang.org/x/tools/go/ssa/identical.go delete mode 100644 vendor/golang.org/x/tools/go/ssa/identical_17.go create mode 100644 vendor/golang.org/x/tools/internal/analysisinternal/analysis.go rename vendor/golang.org/x/tools/{go/analysis/passes/internal/analysisutil => internal/analysisinternal}/extractdoc.go (99%) create mode 100644 vendor/golang.org/x/tools/internal/event/keys/util.go create mode 100644 vendor/golang.org/x/tools/internal/event/tag/tag.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/bexport.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go create mode 100644 vendor/golang.org/x/tools/internal/versions/gover.go create mode 100644 vendor/golang.org/x/tools/internal/versions/types.go create mode 100644 vendor/golang.org/x/tools/internal/versions/types_go121.go create mode 100644 vendor/golang.org/x/tools/internal/versions/types_go122.go create mode 100644 vendor/golang.org/x/tools/internal/versions/versions.go delete mode 100644 vendor/golang.org/x/vuln/client/cache.go delete mode 100644 vendor/golang.org/x/vuln/client/client.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/binary_118.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/binary_not118.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/errors.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/formatting.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/cache.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/source.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/util.go delete mode 100644 vendor/golang.org/x/vuln/cmd/govulncheck/main_testmode.go create mode 100644 vendor/golang.org/x/vuln/internal/buildinfo/README.md create mode 100644 vendor/golang.org/x/vuln/internal/buildinfo/additions_buildinfo.go rename vendor/golang.org/x/vuln/{vulncheck/internal/binscan/scan.go => internal/buildinfo/additions_scan.go} (65%) create mode 100644 vendor/golang.org/x/vuln/internal/buildinfo/buildinfo.go create mode 100644 vendor/golang.org/x/vuln/internal/client/client.go create mode 100644 vendor/golang.org/x/vuln/internal/client/index.go create mode 100644 vendor/golang.org/x/vuln/internal/client/schema.go create mode 100644 vendor/golang.org/x/vuln/internal/client/source.go create mode 100644 vendor/golang.org/x/vuln/internal/gosym/README.md rename vendor/golang.org/x/vuln/{vulncheck => }/internal/gosym/additions.go (68%) rename vendor/golang.org/x/vuln/{vulncheck => }/internal/gosym/pclntab.go (96%) rename vendor/golang.org/x/vuln/{vulncheck => }/internal/gosym/symtab.go (99%) create mode 100644 vendor/golang.org/x/vuln/internal/govulncheck/govulncheck.go create mode 100644 vendor/golang.org/x/vuln/internal/govulncheck/handler.go create mode 100644 vendor/golang.org/x/vuln/internal/govulncheck/jsonhandler.go create mode 100644 vendor/golang.org/x/vuln/internal/osv/osv.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/binary.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/color.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/errors.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/extract.go rename vendor/golang.org/x/vuln/{cmd/govulncheck/internal/govulncheck => internal/scan}/filepath.go (97%) create mode 100644 vendor/golang.org/x/vuln/internal/scan/flags.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/query.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/run.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/source.go rename vendor/golang.org/x/vuln/{cmd/govulncheck => internal/scan}/stdlib.go (86%) create mode 100644 vendor/golang.org/x/vuln/internal/scan/template.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/text.go create mode 100644 vendor/golang.org/x/vuln/internal/scan/util.go create mode 100644 vendor/golang.org/x/vuln/internal/semver/affects.go create mode 100644 vendor/golang.org/x/vuln/internal/semver/fixed.go create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/binary.go rename vendor/golang.org/x/vuln/{ => internal}/vulncheck/doc.go (94%) create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/emit.go rename vendor/golang.org/x/vuln/{ => internal}/vulncheck/entries.go (84%) create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/fetch.go create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/packages.go create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/slicing.go create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/source.go rename vendor/golang.org/x/vuln/{ => internal}/vulncheck/utils.go (58%) create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/vulncheck.go create mode 100644 vendor/golang.org/x/vuln/internal/vulncheck/witness.go create mode 100644 vendor/golang.org/x/vuln/internal/web/url.go delete mode 100644 vendor/golang.org/x/vuln/osv/json.go create mode 100644 vendor/golang.org/x/vuln/scan/scan.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/binary.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/fetch.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/internal/binscan/exe.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/internal/gosym/README.md delete mode 100644 vendor/golang.org/x/vuln/vulncheck/internal/gosym/sym.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/lib.sh delete mode 100644 vendor/golang.org/x/vuln/vulncheck/slicing.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/source.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/vulncheck.go delete mode 100644 vendor/golang.org/x/vuln/vulncheck/witness.go diff --git a/go.mod b/go.mod index 39943319f..fd3fbaa19 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/uber/jaeger-lib v1.5.0 github.com/zenazn/goji v1.0.1 golang.org/x/text v0.14.0 - golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e + golang.org/x/vuln v1.0.4 google.golang.org/grpc v1.60.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 google.golang.org/protobuf v1.33.0 @@ -210,11 +210,11 @@ require ( golang.org/x/crypto v0.18.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 // indirect - golang.org/x/mod v0.10.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.20.0 // indirect - golang.org/x/sync v0.4.0 // indirect + golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.16.0 // indirect - golang.org/x/tools v0.8.0 // indirect + golang.org/x/tools v0.17.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -224,5 +224,5 @@ require ( mvdan.cc/gofumpt v0.4.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect - mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect + mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8 // indirect ) diff --git a/go.sum b/go.sum index 005ae5f4b..896326eb2 100644 --- a/go.sum +++ b/go.sum @@ -120,7 +120,6 @@ github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuP 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 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= 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/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -281,8 +280,8 @@ github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSW github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= 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-cmdtest v0.4.0 h1:ToXh6W5spLp3npJV92tk6d5hIpUPYEzHLkD+rncbyhI= -github.com/google/go-cmdtest v0.4.0/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= +github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU= +github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= 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= @@ -765,8 +764,9 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -843,8 +843,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1020,10 +1020,11 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e h1:5Hq/b1GYIt4/LvB6c4KOX+XyV1iOEjrP8uigwK7EQpU= -golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e/go.mod h1:7tDfEDtOLlzHQRi4Yzfg5seVBSvouUIjyPzBx4q5CxQ= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/vuln v1.0.4 h1:SP0mPeg2PmGCu03V+61EcQiOjmpri2XijexKdzv8Z1I= +golang.org/x/vuln v1.0.4/go.mod h1:NbJdUQhX8jY++FtuhrXs2Eyx0yePo9pF7nPlIjo9aaQ= 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= @@ -1175,8 +1176,8 @@ mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wp mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= -mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= +mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8 h1:VuJo4Mt0EVPychre4fNlDWDuE5AjXtPJpRUWqZDQhaI= +mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8/go.mod h1:Oh/d7dEtzsNHGOq1Cdv8aMm3KdKhVvPbRQcM8WFpBR8= 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= diff --git a/vendor/golang.org/x/exp/maps/maps.go b/vendor/golang.org/x/exp/maps/maps.go deleted file mode 100644 index ecc0dabb7..000000000 --- a/vendor/golang.org/x/exp/maps/maps.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2021 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 maps defines various functions useful with maps of any type. -package maps - -// Keys returns the keys of the map m. -// The keys will be in an indeterminate order. -func Keys[M ~map[K]V, K comparable, V any](m M) []K { - r := make([]K, 0, len(m)) - for k := range m { - r = append(r, k) - } - return r -} - -// Values returns the values of the map m. -// The values will be in an indeterminate order. -func Values[M ~map[K]V, K comparable, V any](m M) []V { - r := make([]V, 0, len(m)) - for _, v := range m { - r = append(r, v) - } - return r -} - -// Equal reports whether two maps contain the same key/value pairs. -// Values are compared using ==. -func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool { - if len(m1) != len(m2) { - return false - } - for k, v1 := range m1 { - if v2, ok := m2[k]; !ok || v1 != v2 { - return false - } - } - return true -} - -// EqualFunc is like Equal, but compares values using eq. -// Keys are still compared with ==. -func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool { - if len(m1) != len(m2) { - return false - } - for k, v1 := range m1 { - if v2, ok := m2[k]; !ok || !eq(v1, v2) { - return false - } - } - return true -} - -// Clear removes all entries from m, leaving it empty. -func Clear[M ~map[K]V, K comparable, V any](m M) { - for k := range m { - delete(m, k) - } -} - -// Clone returns a copy of m. This is a shallow clone: -// the new keys and values are set using ordinary assignment. -func Clone[M ~map[K]V, K comparable, V any](m M) M { - // Preserve nil in case it matters. - if m == nil { - return nil - } - r := make(M, len(m)) - for k, v := range m { - r[k] = v - } - return r -} - -// Copy copies all key/value pairs in src adding them to dst. -// When a key in src is already present in dst, -// the value in dst will be overwritten by the value associated -// with the key in src. -func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) { - for k, v := range src { - dst[k] = v - } -} - -// DeleteFunc deletes any key/value pairs from m for which del returns true. -func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) { - for k, v := range m { - if del(k, v) { - delete(m, k) - } - } -} diff --git a/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go b/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go index 2681af35a..150f887e7 100644 --- a/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go +++ b/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go @@ -13,7 +13,7 @@ import ( "sync" ) -// Regexp is a wrapper around regexp.Regexp, where the underlying regexp will be +// Regexp is a wrapper around [regexp.Regexp], where the underlying regexp will be // compiled the first time it is needed. type Regexp struct { str string diff --git a/vendor/golang.org/x/mod/modfile/print.go b/vendor/golang.org/x/mod/modfile/print.go index 524f93022..2a0123d4b 100644 --- a/vendor/golang.org/x/mod/modfile/print.go +++ b/vendor/golang.org/x/mod/modfile/print.go @@ -16,7 +16,13 @@ import ( func Format(f *FileSyntax) []byte { pr := &printer{} pr.file(f) - return pr.Bytes() + + // remove trailing blank lines + b := pr.Bytes() + for len(b) > 0 && b[len(b)-1] == '\n' && (len(b) == 1 || b[len(b)-2] == '\n') { + b = b[:len(b)-1] + } + return b } // A printer collects the state during printing of a file or expression. @@ -59,7 +65,11 @@ func (p *printer) newline() { } p.trim() - p.printf("\n") + if b := p.Bytes(); len(b) == 0 || (len(b) >= 2 && b[len(b)-1] == '\n' && b[len(b)-2] == '\n') { + // skip the blank line at top of file or after a blank line + } else { + p.printf("\n") + } for i := 0; i < p.margin; i++ { p.printf("\t") } diff --git a/vendor/golang.org/x/mod/modfile/read.go b/vendor/golang.org/x/mod/modfile/read.go index a503bc210..5b5bb5e11 100644 --- a/vendor/golang.org/x/mod/modfile/read.go +++ b/vendor/golang.org/x/mod/modfile/read.go @@ -65,7 +65,7 @@ type Comments struct { } // Comment returns the receiver. This isn't useful by itself, but -// a Comments struct is embedded into all the expression +// a [Comments] struct is embedded into all the expression // implementation types, and this gives each of those a Comment // method to satisfy the Expr interface. func (c *Comments) Comment() *Comments { diff --git a/vendor/golang.org/x/mod/modfile/rule.go b/vendor/golang.org/x/mod/modfile/rule.go index 6bcde8fab..35fd1f534 100644 --- a/vendor/golang.org/x/mod/modfile/rule.go +++ b/vendor/golang.org/x/mod/modfile/rule.go @@ -5,17 +5,17 @@ // Package modfile implements a parser and formatter for go.mod files. // // The go.mod syntax is described in -// https://golang.org/cmd/go/#hdr-The_go_mod_file. +// https://pkg.go.dev/cmd/go/#hdr-The_go_mod_file. // -// The Parse and ParseLax functions both parse a go.mod file and return an +// The [Parse] and [ParseLax] functions both parse a go.mod file and return an // abstract syntax tree. ParseLax ignores unknown statements and may be used to // parse go.mod files that may have been developed with newer versions of Go. // -// The File struct returned by Parse and ParseLax represent an abstract -// go.mod file. File has several methods like AddNewRequire and DropReplace -// that can be used to programmatically edit a file. +// The [File] struct returned by Parse and ParseLax represent an abstract +// go.mod file. File has several methods like [File.AddNewRequire] and +// [File.DropReplace] that can be used to programmatically edit a file. // -// The Format function formats a File back to a byte slice which can be +// The [Format] function formats a File back to a byte slice which can be // written to a file. package modfile @@ -35,12 +35,13 @@ import ( // A File is the parsed, interpreted form of a go.mod file. type File struct { - Module *Module - Go *Go - Require []*Require - Exclude []*Exclude - Replace []*Replace - Retract []*Retract + Module *Module + Go *Go + Toolchain *Toolchain + Require []*Require + Exclude []*Exclude + Replace []*Replace + Retract []*Retract Syntax *FileSyntax } @@ -58,6 +59,12 @@ type Go struct { Syntax *Line } +// A Toolchain is the toolchain statement. +type Toolchain struct { + Name string // "go1.21rc1" + Syntax *Line +} + // An Exclude is a single exclude statement. type Exclude struct { Mod module.Version @@ -219,7 +226,7 @@ var dontFixRetract VersionFixer = func(_, vers string) (string, error) { // data is the content of the file. // // fix is an optional function that canonicalizes module versions. -// If fix is nil, all module versions must be canonical (module.CanonicalVersion +// If fix is nil, all module versions must be canonical ([module.CanonicalVersion] // must return the same string). func Parse(file string, data []byte, fix VersionFixer) (*File, error) { return parseToFile(file, data, fix, true) @@ -296,9 +303,13 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parse return f, nil } -var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) +var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))?([a-z]+[0-9]+)?$`) var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9].*)$`) +// Toolchains must be named beginning with `go1`, +// like "go1.20.3" or "go1.20.3-gccgo". As a special case, "default" is also permitted. +var ToolchainRE = lazyregexp.New(`^default$|^go1($|\.)`) + func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool) { // If strict is false, this module is a dependency. // We ignore all unknown directives as well as main-module-only @@ -356,7 +367,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a } } if !fixed { - errorf("invalid go version '%s': must match format 1.23", args[0]) + errorf("invalid go version '%s': must match format 1.23.0", args[0]) return } } @@ -364,6 +375,21 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a f.Go = &Go{Syntax: line} f.Go.Version = args[0] + case "toolchain": + if f.Toolchain != nil { + errorf("repeated toolchain statement") + return + } + if len(args) != 1 { + errorf("toolchain directive expects exactly one argument") + return + } else if strict && !ToolchainRE.MatchString(args[0]) { + errorf("invalid toolchain version '%s': must match format go1.23.0 or local", args[0]) + return + } + f.Toolchain = &Toolchain{Syntax: line} + f.Toolchain.Name = args[0] + case "module": if f.Module != nil { errorf("repeated module statement") @@ -516,7 +542,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V if strings.Contains(ns, "@") { return nil, errorf("replacement module must match format 'path version', not 'path@version'") } - return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") + return nil, errorf("replacement module without version must be directory path (rooted or starting with . or ..)") } if filepath.Separator == '/' && strings.Contains(ns, `\`) { return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)") @@ -529,7 +555,6 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V } if IsDirectoryPath(ns) { return nil, errorf("replacement module directory path %q cannot have version", ns) - } } return &Replace{ @@ -612,6 +637,22 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, f.Go = &Go{Syntax: line} f.Go.Version = args[0] + case "toolchain": + if f.Toolchain != nil { + errorf("repeated toolchain statement") + return + } + if len(args) != 1 { + errorf("toolchain directive expects exactly one argument") + return + } else if !ToolchainRE.MatchString(args[0]) { + errorf("invalid toolchain version '%s': must match format go1.23 or local", args[0]) + return + } + + f.Toolchain = &Toolchain{Syntax: line} + f.Toolchain.Name = args[0] + case "use": if len(args) != 1 { errorf("usage: %s local/dir", verb) @@ -637,14 +678,15 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, } } -// IsDirectoryPath reports whether the given path should be interpreted -// as a directory path. Just like on the go command line, relative paths +// IsDirectoryPath reports whether the given path should be interpreted as a directory path. +// Just like on the go command line, relative paths starting with a '.' or '..' path component // and rooted paths are directory paths; the rest are module paths. func IsDirectoryPath(ns string) bool { // Because go.mod files can move from one system to another, // we check all known path syntaxes, both Unix and Windows. - return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") || - strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) || + return ns == "." || strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, `.\`) || + ns == ".." || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, `..\`) || + strings.HasPrefix(ns, "/") || strings.HasPrefix(ns, `\`) || len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':' } @@ -881,7 +923,7 @@ func (f *File) Format() ([]byte, error) { } // Cleanup cleans up the file f after any edit operations. -// To avoid quadratic behavior, modifications like DropRequire +// To avoid quadratic behavior, modifications like [File.DropRequire] // clear the entry but do not remove it from the slice. // Cleanup cleans out all the cleared entries. func (f *File) Cleanup() { @@ -926,7 +968,7 @@ func (f *File) Cleanup() { func (f *File) AddGoStmt(version string) error { if !GoVersionRE.MatchString(version) { - return fmt.Errorf("invalid language version string %q", version) + return fmt.Errorf("invalid language version %q", version) } if f.Go == nil { var hint Expr @@ -944,6 +986,44 @@ func (f *File) AddGoStmt(version string) error { return nil } +// DropGoStmt deletes the go statement from the file. +func (f *File) DropGoStmt() { + if f.Go != nil { + f.Go.Syntax.markRemoved() + f.Go = nil + } +} + +// DropToolchainStmt deletes the toolchain statement from the file. +func (f *File) DropToolchainStmt() { + if f.Toolchain != nil { + f.Toolchain.Syntax.markRemoved() + f.Toolchain = nil + } +} + +func (f *File) AddToolchainStmt(name string) error { + if !ToolchainRE.MatchString(name) { + return fmt.Errorf("invalid toolchain name %q", name) + } + if f.Toolchain == nil { + var hint Expr + if f.Go != nil && f.Go.Syntax != nil { + hint = f.Go.Syntax + } else if f.Module != nil && f.Module.Syntax != nil { + hint = f.Module.Syntax + } + f.Toolchain = &Toolchain{ + Name: name, + Syntax: f.Syntax.addLine(hint, "toolchain", name), + } + } else { + f.Toolchain.Name = name + f.Syntax.updateLine(f.Toolchain.Syntax, "toolchain", name) + } + return nil +} + // AddRequire sets the first require line for path to version vers, // preserving any existing comments for that line and removing all // other lines for path. @@ -995,8 +1075,8 @@ func (f *File) AddNewRequire(path, vers string, indirect bool) { // The requirements in req must specify at most one distinct version for each // module path. // -// If any existing requirements may be removed, the caller should call Cleanup -// after all edits are complete. +// If any existing requirements may be removed, the caller should call +// [File.Cleanup] after all edits are complete. func (f *File) SetRequire(req []*Require) { type elem struct { version string @@ -1387,13 +1467,21 @@ func (f *File) DropRetract(vi VersionInterval) error { func (f *File) SortBlocks() { f.removeDups() // otherwise sorting is unsafe + // semanticSortForExcludeVersionV is the Go version (plus leading "v") at which + // lines in exclude blocks start to use semantic sort instead of lexicographic sort. + // See go.dev/issue/60028. + const semanticSortForExcludeVersionV = "v1.21" + useSemanticSortForExclude := f.Go != nil && semver.Compare("v"+f.Go.Version, semanticSortForExcludeVersionV) >= 0 + for _, stmt := range f.Syntax.Stmt { block, ok := stmt.(*LineBlock) if !ok { continue } less := lineLess - if block.Token[0] == "retract" { + if block.Token[0] == "exclude" && useSemanticSortForExclude { + less = lineExcludeLess + } else if block.Token[0] == "retract" { less = lineRetractLess } sort.SliceStable(block.Line, func(i, j int) bool { @@ -1496,6 +1584,22 @@ func lineLess(li, lj *Line) bool { return len(li.Token) < len(lj.Token) } +// lineExcludeLess reports whether li should be sorted before lj for lines in +// an "exclude" block. +func lineExcludeLess(li, lj *Line) bool { + if len(li.Token) != 2 || len(lj.Token) != 2 { + // Not a known exclude specification. + // Fall back to sorting lexicographically. + return lineLess(li, lj) + } + // An exclude specification has two tokens: ModulePath and Version. + // Compare module path by string order and version by semver rules. + if pi, pj := li.Token[0], lj.Token[0]; pi != pj { + return pi < pj + } + return semver.Compare(li.Token[1], lj.Token[1]) < 0 +} + // lineRetractLess returns whether li should be sorted before lj for lines in // a "retract" block. It treats each line as a version interval. Single versions // are compared as if they were intervals with the same low and high version. diff --git a/vendor/golang.org/x/mod/modfile/work.go b/vendor/golang.org/x/mod/modfile/work.go index 0c0e52152..d7b99376e 100644 --- a/vendor/golang.org/x/mod/modfile/work.go +++ b/vendor/golang.org/x/mod/modfile/work.go @@ -12,9 +12,10 @@ import ( // A WorkFile is the parsed, interpreted form of a go.work file. type WorkFile struct { - Go *Go - Use []*Use - Replace []*Replace + Go *Go + Toolchain *Toolchain + Use []*Use + Replace []*Replace Syntax *FileSyntax } @@ -33,7 +34,7 @@ type Use struct { // data is the content of the file. // // fix is an optional function that canonicalizes module versions. -// If fix is nil, all module versions must be canonical (module.CanonicalVersion +// If fix is nil, all module versions must be canonical ([module.CanonicalVersion] // must return the same string). func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) { fs, err := parse(file, data) @@ -82,7 +83,7 @@ func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) { } // Cleanup cleans up the file f after any edit operations. -// To avoid quadratic behavior, modifications like DropRequire +// To avoid quadratic behavior, modifications like [WorkFile.DropRequire] // clear the entry but do not remove it from the slice. // Cleanup cleans out all the cleared entries. func (f *WorkFile) Cleanup() { @@ -109,7 +110,7 @@ func (f *WorkFile) Cleanup() { func (f *WorkFile) AddGoStmt(version string) error { if !GoVersionRE.MatchString(version) { - return fmt.Errorf("invalid language version string %q", version) + return fmt.Errorf("invalid language version %q", version) } if f.Go == nil { stmt := &Line{Token: []string{"go", version}} @@ -117,7 +118,7 @@ func (f *WorkFile) AddGoStmt(version string) error { Version: version, Syntax: stmt, } - // Find the first non-comment-only block that's and add + // Find the first non-comment-only block and add // the go statement before it. That will keep file comments at the top. i := 0 for i = 0; i < len(f.Syntax.Stmt); i++ { @@ -133,6 +134,56 @@ func (f *WorkFile) AddGoStmt(version string) error { return nil } +func (f *WorkFile) AddToolchainStmt(name string) error { + if !ToolchainRE.MatchString(name) { + return fmt.Errorf("invalid toolchain name %q", name) + } + if f.Toolchain == nil { + stmt := &Line{Token: []string{"toolchain", name}} + f.Toolchain = &Toolchain{ + Name: name, + Syntax: stmt, + } + // Find the go line and add the toolchain line after it. + // Or else find the first non-comment-only block and add + // the toolchain line before it. That will keep file comments at the top. + i := 0 + for i = 0; i < len(f.Syntax.Stmt); i++ { + if line, ok := f.Syntax.Stmt[i].(*Line); ok && len(line.Token) > 0 && line.Token[0] == "go" { + i++ + goto Found + } + } + for i = 0; i < len(f.Syntax.Stmt); i++ { + if _, ok := f.Syntax.Stmt[i].(*CommentBlock); !ok { + break + } + } + Found: + f.Syntax.Stmt = append(append(f.Syntax.Stmt[:i:i], stmt), f.Syntax.Stmt[i:]...) + } else { + f.Toolchain.Name = name + f.Syntax.updateLine(f.Toolchain.Syntax, "toolchain", name) + } + return nil +} + +// DropGoStmt deletes the go statement from the file. +func (f *WorkFile) DropGoStmt() { + if f.Go != nil { + f.Go.Syntax.markRemoved() + f.Go = nil + } +} + +// DropToolchainStmt deletes the toolchain statement from the file. +func (f *WorkFile) DropToolchainStmt() { + if f.Toolchain != nil { + f.Toolchain.Syntax.markRemoved() + f.Toolchain = nil + } +} + func (f *WorkFile) AddUse(diskPath, modulePath string) error { need := true for _, d := range f.Use { diff --git a/vendor/golang.org/x/mod/module/module.go b/vendor/golang.org/x/mod/module/module.go index e9dec6e61..2a364b229 100644 --- a/vendor/golang.org/x/mod/module/module.go +++ b/vendor/golang.org/x/mod/module/module.go @@ -4,7 +4,7 @@ // Package module defines the module.Version type along with support code. // -// The module.Version type is a simple Path, Version pair: +// The [module.Version] type is a simple Path, Version pair: // // type Version struct { // Path string @@ -12,7 +12,7 @@ // } // // There are no restrictions imposed directly by use of this structure, -// but additional checking functions, most notably Check, verify that +// but additional checking functions, most notably [Check], verify that // a particular path, version pair is valid. // // # Escaped Paths @@ -140,7 +140,7 @@ type ModuleError struct { Err error } -// VersionError returns a ModuleError derived from a Version and error, +// VersionError returns a [ModuleError] derived from a [Version] and error, // or err itself if it is already such an error. func VersionError(v Version, err error) error { var mErr *ModuleError @@ -169,7 +169,7 @@ func (e *ModuleError) Unwrap() error { return e.Err } // An InvalidVersionError indicates an error specific to a version, with the // module path unknown or specified externally. // -// A ModuleError may wrap an InvalidVersionError, but an InvalidVersionError +// A [ModuleError] may wrap an InvalidVersionError, but an InvalidVersionError // must not wrap a ModuleError. type InvalidVersionError struct { Version string @@ -193,8 +193,8 @@ func (e *InvalidVersionError) Error() string { func (e *InvalidVersionError) Unwrap() error { return e.Err } // An InvalidPathError indicates a module, import, or file path doesn't -// satisfy all naming constraints. See CheckPath, CheckImportPath, -// and CheckFilePath for specific restrictions. +// satisfy all naming constraints. See [CheckPath], [CheckImportPath], +// and [CheckFilePath] for specific restrictions. type InvalidPathError struct { Kind string // "module", "import", or "file" Path string @@ -294,7 +294,7 @@ func fileNameOK(r rune) bool { } // CheckPath checks that a module path is valid. -// A valid module path is a valid import path, as checked by CheckImportPath, +// A valid module path is a valid import path, as checked by [CheckImportPath], // with three additional constraints. // First, the leading path element (up to the first slash, if any), // by convention a domain name, must contain only lower-case ASCII letters, @@ -380,7 +380,7 @@ const ( // checkPath returns an error describing why the path is not valid. // Because these checks apply to module, import, and file paths, // and because other checks may be applied, the caller is expected to wrap -// this error with InvalidPathError. +// this error with [InvalidPathError]. func checkPath(path string, kind pathKind) error { if !utf8.ValidString(path) { return fmt.Errorf("invalid UTF-8") @@ -532,7 +532,7 @@ var badWindowsNames = []string{ // they require ".vN" instead of "/vN", and for all N, not just N >= 2. // SplitPathVersion returns with ok = false when presented with // a path whose last path element does not satisfy the constraints -// applied by CheckPath, such as "example.com/pkg/v1" or "example.com/pkg/v1.2". +// applied by [CheckPath], such as "example.com/pkg/v1" or "example.com/pkg/v1.2". func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) { if strings.HasPrefix(path, "gopkg.in/") { return splitGopkgIn(path) @@ -582,7 +582,7 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { // MatchPathMajor reports whether the semantic version v // matches the path major version pathMajor. // -// MatchPathMajor returns true if and only if CheckPathMajor returns nil. +// MatchPathMajor returns true if and only if [CheckPathMajor] returns nil. func MatchPathMajor(v, pathMajor string) bool { return CheckPathMajor(v, pathMajor) == nil } @@ -622,7 +622,7 @@ func CheckPathMajor(v, pathMajor string) error { // PathMajorPrefix returns the major-version tag prefix implied by pathMajor. // An empty PathMajorPrefix allows either v0 or v1. // -// Note that MatchPathMajor may accept some versions that do not actually begin +// Note that [MatchPathMajor] may accept some versions that do not actually begin // with this prefix: namely, it accepts a 'v0.0.0-' prefix for a '.v1' // pathMajor, even though that pathMajor implies 'v1' tagging. func PathMajorPrefix(pathMajor string) string { @@ -643,7 +643,7 @@ func PathMajorPrefix(pathMajor string) string { } // CanonicalVersion returns the canonical form of the version string v. -// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible". +// It is the same as [semver.Canonical] except that it preserves the special build suffix "+incompatible". func CanonicalVersion(v string) string { cv := semver.Canonical(v) if semver.Build(v) == "+incompatible" { @@ -652,8 +652,8 @@ func CanonicalVersion(v string) string { return cv } -// Sort sorts the list by Path, breaking ties by comparing Version fields. -// The Version fields are interpreted as semantic versions (using semver.Compare) +// Sort sorts the list by Path, breaking ties by comparing [Version] fields. +// The Version fields are interpreted as semantic versions (using [semver.Compare]) // optionally followed by a tie-breaking suffix introduced by a slash character, // like in "v0.0.1/go.mod". func Sort(list []Version) { @@ -793,7 +793,7 @@ func unescapeString(escaped string) (string, bool) { } // MatchPrefixPatterns reports whether any path prefix of target matches one of -// the glob patterns (as defined by path.Match) in the comma-separated globs +// the glob patterns (as defined by [path.Match]) in the comma-separated globs // list. This implements the algorithm used when matching a module path to the // GOPRIVATE environment variable, as described by 'go help module-private'. // diff --git a/vendor/golang.org/x/mod/module/pseudo.go b/vendor/golang.org/x/mod/module/pseudo.go index f04ad3788..9cf19d325 100644 --- a/vendor/golang.org/x/mod/module/pseudo.go +++ b/vendor/golang.org/x/mod/module/pseudo.go @@ -125,7 +125,7 @@ func IsPseudoVersion(v string) bool { } // IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base, -// timestamp, and revision, as returned by ZeroPseudoVersion. +// timestamp, and revision, as returned by [ZeroPseudoVersion]. func IsZeroPseudoVersion(v string) bool { return v == ZeroPseudoVersion(semver.Major(v)) } diff --git a/vendor/golang.org/x/mod/semver/semver.go b/vendor/golang.org/x/mod/semver/semver.go index a30a22bf2..9a2dfd33a 100644 --- a/vendor/golang.org/x/mod/semver/semver.go +++ b/vendor/golang.org/x/mod/semver/semver.go @@ -140,7 +140,7 @@ func Compare(v, w string) int { // Max canonicalizes its arguments and then returns the version string // that compares greater. // -// Deprecated: use Compare instead. In most cases, returning a canonicalized +// Deprecated: use [Compare] instead. In most cases, returning a canonicalized // version is not expected or desired. func Max(v, w string) string { v = Canonical(v) @@ -151,7 +151,7 @@ func Max(v, w string) string { return w } -// ByVersion implements sort.Interface for sorting semantic version strings. +// ByVersion implements [sort.Interface] for sorting semantic version strings. type ByVersion []string func (vs ByVersion) Len() int { return len(vs) } @@ -164,7 +164,7 @@ func (vs ByVersion) Less(i, j int) bool { return vs[i] < vs[j] } -// Sort sorts a list of semantic version strings using ByVersion. +// Sort sorts a list of semantic version strings using [ByVersion]. func Sort(list []string) { sort.Sort(ByVersion(list)) } diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index b18efb743..948a3ee63 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -4,6 +4,9 @@ // Package errgroup provides synchronization, error propagation, and Context // cancelation for groups of goroutines working on subtasks of a common task. +// +// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks +// returning errors. package errgroup import ( diff --git a/vendor/golang.org/x/sync/errgroup/go120.go b/vendor/golang.org/x/sync/errgroup/go120.go index 7d419d376..f93c740b6 100644 --- a/vendor/golang.org/x/sync/errgroup/go120.go +++ b/vendor/golang.org/x/sync/errgroup/go120.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build go1.20 -// +build go1.20 package errgroup diff --git a/vendor/golang.org/x/sync/errgroup/pre_go120.go b/vendor/golang.org/x/sync/errgroup/pre_go120.go index 1795c18ac..88ce33434 100644 --- a/vendor/golang.org/x/sync/errgroup/pre_go120.go +++ b/vendor/golang.org/x/sync/errgroup/pre_go120.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !go1.20 -// +build !go1.20 package errgroup diff --git a/vendor/golang.org/x/sys/execabs/execabs.go b/vendor/golang.org/x/sys/execabs/execabs.go deleted file mode 100644 index 3bf40fdfe..000000000 --- a/vendor/golang.org/x/sys/execabs/execabs.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2020 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 execabs is a drop-in replacement for os/exec -// that requires PATH lookups to find absolute paths. -// That is, execabs.Command("cmd") runs the same PATH lookup -// as exec.Command("cmd"), but if the result is a path -// which is relative, the Run and Start methods will report -// an error instead of running the executable. -// -// See https://blog.golang.org/path-security for more information -// about when it may be necessary or appropriate to use this package. -package execabs - -import ( - "context" - "fmt" - "os/exec" - "path/filepath" - "reflect" - "unsafe" -) - -// ErrNotFound is the error resulting if a path search failed to find an executable file. -// It is an alias for exec.ErrNotFound. -var ErrNotFound = exec.ErrNotFound - -// Cmd represents an external command being prepared or run. -// It is an alias for exec.Cmd. -type Cmd = exec.Cmd - -// Error is returned by LookPath when it fails to classify a file as an executable. -// It is an alias for exec.Error. -type Error = exec.Error - -// An ExitError reports an unsuccessful exit by a command. -// It is an alias for exec.ExitError. -type ExitError = exec.ExitError - -func relError(file, path string) error { - return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path) -} - -// LookPath searches for an executable named file in the directories -// named by the PATH environment variable. If file contains a slash, -// it is tried directly and the PATH is not consulted. The result will be -// an absolute path. -// -// LookPath differs from exec.LookPath in its handling of PATH lookups, -// which are used for file names without slashes. If exec.LookPath's -// PATH lookup would have returned an executable from the current directory, -// LookPath instead returns an error. -func LookPath(file string) (string, error) { - path, err := exec.LookPath(file) - if err != nil && !isGo119ErrDot(err) { - return "", err - } - if filepath.Base(file) == file && !filepath.IsAbs(path) { - return "", relError(file, path) - } - return path, nil -} - -func fixCmd(name string, cmd *exec.Cmd) { - if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) && !isGo119ErrFieldSet(cmd) { - // exec.Command was called with a bare binary name and - // exec.LookPath returned a path which is not absolute. - // Set cmd.lookPathErr and clear cmd.Path so that it - // cannot be run. - lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) - if *lookPathErr == nil { - *lookPathErr = relError(name, cmd.Path) - } - cmd.Path = "" - } -} - -// CommandContext is like Command but includes a context. -// -// The provided context is used to kill the process (by calling os.Process.Kill) -// if the context becomes done before the command completes on its own. -func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { - cmd := exec.CommandContext(ctx, name, arg...) - fixCmd(name, cmd) - return cmd - -} - -// Command returns the Cmd struct to execute the named program with the given arguments. -// See exec.Command for most details. -// -// Command differs from exec.Command in its handling of PATH lookups, -// which are used when the program name contains no slashes. -// If exec.Command would have returned an exec.Cmd configured to run an -// executable from the current directory, Command instead -// returns an exec.Cmd that will return an error from Start or Run. -func Command(name string, arg ...string) *exec.Cmd { - cmd := exec.Command(name, arg...) - fixCmd(name, cmd) - return cmd -} diff --git a/vendor/golang.org/x/sys/execabs/execabs_go118.go b/vendor/golang.org/x/sys/execabs/execabs_go118.go deleted file mode 100644 index 5627d70e3..000000000 --- a/vendor/golang.org/x/sys/execabs/execabs_go118.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.19 - -package execabs - -import "os/exec" - -func isGo119ErrDot(err error) bool { - return false -} - -func isGo119ErrFieldSet(cmd *exec.Cmd) bool { - return false -} diff --git a/vendor/golang.org/x/sys/execabs/execabs_go119.go b/vendor/golang.org/x/sys/execabs/execabs_go119.go deleted file mode 100644 index d60ab1b41..000000000 --- a/vendor/golang.org/x/sys/execabs/execabs_go119.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.19 - -package execabs - -import ( - "errors" - "os/exec" -) - -func isGo119ErrDot(err error) bool { - return errors.Is(err, exec.ErrDot) -} - -func isGo119ErrFieldSet(cmd *exec.Cmd) bool { - return cmd.Err != nil -} diff --git a/vendor/golang.org/x/tools/go/analysis/analysis.go b/vendor/golang.org/x/tools/go/analysis/analysis.go index e51e58b3d..5da33c7e6 100644 --- a/vendor/golang.org/x/tools/go/analysis/analysis.go +++ b/vendor/golang.org/x/tools/go/analysis/analysis.go @@ -139,28 +139,24 @@ type Pass struct { // See comments for ExportObjectFact. ExportPackageFact func(fact Fact) - // AllPackageFacts returns a new slice containing all package facts of the analysis's FactTypes - // in unspecified order. - // WARNING: This is an experimental API and may change in the future. + // AllPackageFacts returns a new slice containing all package + // facts of the analysis's FactTypes in unspecified order. AllPackageFacts func() []PackageFact - // AllObjectFacts returns a new slice containing all object facts of the analysis's FactTypes - // in unspecified order. - // WARNING: This is an experimental API and may change in the future. + // AllObjectFacts returns a new slice containing all object + // facts of the analysis's FactTypes in unspecified order. AllObjectFacts func() []ObjectFact /* Further fields may be added in future. */ } // PackageFact is a package together with an associated fact. -// WARNING: This is an experimental API and may change in the future. type PackageFact struct { Package *types.Package Fact Fact } // ObjectFact is an object together with an associated fact. -// WARNING: This is an experimental API and may change in the future. type ObjectFact struct { Object types.Object Fact Fact diff --git a/vendor/golang.org/x/tools/go/analysis/diagnostic.go b/vendor/golang.org/x/tools/go/analysis/diagnostic.go index 7646ad0d4..f67c97294 100644 --- a/vendor/golang.org/x/tools/go/analysis/diagnostic.go +++ b/vendor/golang.org/x/tools/go/analysis/diagnostic.go @@ -31,14 +31,13 @@ type Diagnostic struct { // see https://pkg.go.dev/net/url#URL.ResolveReference. URL string - // SuggestedFixes contains suggested fixes for a diagnostic which can be used to perform - // edits to a file that address the diagnostic. - // TODO(matloob): Should multiple SuggestedFixes be allowed for a diagnostic? + // SuggestedFixes contains suggested fixes for a diagnostic + // which can be used to perform edits to a file that address + // the diagnostic. + // // Diagnostics should not contain SuggestedFixes that overlap. - // Experimental: This API is experimental and may change in the future. SuggestedFixes []SuggestedFix // optional - // Experimental: This API is experimental and may change in the future. Related []RelatedInformation // optional } @@ -52,12 +51,12 @@ type RelatedInformation struct { Message string } -// A SuggestedFix is a code change associated with a Diagnostic that a user can choose -// to apply to their code. Usually the SuggestedFix is meant to fix the issue flagged -// by the diagnostic. -// TextEdits for a SuggestedFix should not overlap. TextEdits for a SuggestedFix -// should not contain edits for other packages. -// Experimental: This API is experimental and may change in the future. +// A SuggestedFix is a code change associated with a Diagnostic that a +// user can choose to apply to their code. Usually the SuggestedFix is +// meant to fix the issue flagged by the diagnostic. +// +// TextEdits for a SuggestedFix should not overlap, +// nor contain edits for other packages. type SuggestedFix struct { // A description for this suggested fix to be shown to a user deciding // whether to accept it. @@ -67,7 +66,6 @@ type SuggestedFix struct { // A TextEdit represents the replacement of the code between Pos and End with the new text. // Each TextEdit should apply to a single file. End should not be earlier in the file than Pos. -// Experimental: This API is experimental and may change in the future. type TextEdit struct { // For a pure insertion, End can either be set to Pos or token.NoPos. Pos token.Pos diff --git a/vendor/golang.org/x/tools/go/analysis/doc.go b/vendor/golang.org/x/tools/go/analysis/doc.go index c5429c9e2..44867d599 100644 --- a/vendor/golang.org/x/tools/go/analysis/doc.go +++ b/vendor/golang.org/x/tools/go/analysis/doc.go @@ -191,7 +191,7 @@ and buildtag, inspect the raw text of Go source files or even non-Go files such as assembly. To report a diagnostic against a line of a raw text file, use the following sequence: - content, err := ioutil.ReadFile(filename) + content, err := os.ReadFile(filename) if err != nil { ... } tf := fset.AddFile(filename, -1, len(content)) tf.SetLinesForContent(content) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go index 10489bea1..3bfd50122 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go @@ -18,6 +18,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" ) @@ -77,7 +78,7 @@ func run(pass *analysis.Pass) (interface{}, error) { // isMapIndex returns true if e is a map index expression. func isMapIndex(info *types.Info, e ast.Expr) bool { - if idx, ok := analysisutil.Unparen(e).(*ast.IndexExpr); ok { + if idx, ok := astutil.Unparen(e).(*ast.IndexExpr); ok { if typ := info.Types[idx.X].Type; typ != nil { _, ok := typ.Underlying().(*types.Map) return ok diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go index 5978b9b1f..931f9ca75 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go @@ -8,12 +8,12 @@ import ( _ "embed" "go/ast" "go/token" - "go/types" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" ) //go:embed doc.go @@ -29,6 +29,10 @@ var Analyzer = &analysis.Analyzer{ } func run(pass *analysis.Pass) (interface{}, error) { + if !analysisutil.Imports(pass.Pkg, "sync/atomic") { + return nil, nil // doesn't directly import sync/atomic + } + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -48,18 +52,8 @@ func run(pass *analysis.Pass) (interface{}, error) { if !ok { continue } - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - continue - } - pkgIdent, _ := sel.X.(*ast.Ident) - pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName) - if !ok || pkgName.Imported().Path() != "sync/atomic" { - continue - } - - switch sel.Sel.Name { - case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr": + fn := typeutil.StaticCallee(pass.TypesInfo, call) + if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") { checkAtomicAddAssignment(pass, n.Lhs[i], call) } } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go index fc2ce3052..aff6d25b3 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go @@ -18,6 +18,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" ) const Doc = "check for non-64-bits-aligned arguments to sync/atomic functions" @@ -42,31 +43,20 @@ func run(pass *analysis.Pass) (interface{}, error) { nodeFilter := []ast.Node{ (*ast.CallExpr)(nil), } + funcNames := []string{ + "AddInt64", "AddUint64", + "LoadInt64", "LoadUint64", + "StoreInt64", "StoreUint64", + "SwapInt64", "SwapUint64", + "CompareAndSwapInt64", "CompareAndSwapUint64", + } inspect.Preorder(nodeFilter, func(node ast.Node) { call := node.(*ast.CallExpr) - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return - } - pkgIdent, ok := sel.X.(*ast.Ident) - if !ok { - return - } - pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName) - if !ok || pkgName.Imported().Path() != "sync/atomic" { - return - } - - switch sel.Sel.Name { - case "AddInt64", "AddUint64", - "LoadInt64", "LoadUint64", - "StoreInt64", "StoreUint64", - "SwapInt64", "SwapUint64", - "CompareAndSwapInt64", "CompareAndSwapUint64": - + fn := typeutil.StaticCallee(pass.TypesInfo, call) + if analysisutil.IsFunctionNamed(fn, "sync/atomic", funcNames...) { // For all the listed functions, the expression to check is always the first function argument. - check64BitAlignment(pass, sel.Sel.Name, call.Args[0]) + check64BitAlignment(pass, fn.Name(), call.Args[0]) } }) @@ -75,8 +65,8 @@ func run(pass *analysis.Pass) (interface{}, error) { func check64BitAlignment(pass *analysis.Pass, funcName string, arg ast.Expr) { // Checks the argument is made of the address operator (&) applied to - // to a struct field (as opposed to a variable as the first word of - // uint64 and int64 variables can be relied upon to be 64-bit aligned. + // a struct field (as opposed to a variable as the first word of + // uint64 and int64 variables can be relied upon to be 64-bit aligned). unary, ok := arg.(*ast.UnaryExpr) if !ok || unary.Op != token.AND { return diff --git a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go index 4219f087b..564329774 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" ) @@ -83,7 +84,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[* i := 0 var sets [][]ast.Expr for j := 0; j <= len(exprs); j++ { - if j == len(exprs) || hasSideEffects(info, exprs[j]) { + if j == len(exprs) || analysisutil.HasSideEffects(info, exprs[j]) { if i < j { sets = append(sets, exprs[i:j]) } @@ -162,46 +163,13 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) { } } -// hasSideEffects reports whether evaluation of e has side effects. -func hasSideEffects(info *types.Info, e ast.Expr) bool { - safe := true - ast.Inspect(e, func(node ast.Node) bool { - switch n := node.(type) { - case *ast.CallExpr: - typVal := info.Types[n.Fun] - switch { - case typVal.IsType(): - // Type conversion, which is safe. - case typVal.IsBuiltin(): - // Builtin func, conservatively assumed to not - // be safe for now. - safe = false - return false - default: - // A non-builtin func or method call. - // Conservatively assume that all of them have - // side effects for now. - safe = false - return false - } - case *ast.UnaryExpr: - if n.Op == token.ARROW { - safe = false - return false - } - } - return true - }) - return !safe -} - // split returns a slice of all subexpressions in e that are connected by op. // For example, given 'a || (b || c) || d' with the or op, // split returns []{d, c, b, a}. // seen[e] is already true; any newly processed exprs are added to seen. func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.Expr) { for { - e = unparen(e) + e = astutil.Unparen(e) if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok { seen[b] = true exprs = append(exprs, op.split(b.Y, seen)...) @@ -213,14 +181,3 @@ func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.E } return } - -// unparen returns e with any enclosing parentheses stripped. -func unparen(e ast.Expr) ast.Expr { - for { - p, ok := e.(*ast.ParenExpr) - if !ok { - return e - } - e = p.X - } -} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go index ad42f39a8..f077ea282 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go @@ -6,8 +6,6 @@ // representation of an error-free package and returns the set of all // functions within it. It does not report any diagnostics itself but // may be used as an input to other analyzers. -// -// THIS INTERFACE IS EXPERIMENTAL AND MAY BE SUBJECT TO INCOMPATIBLE CHANGE. package buildssa import ( @@ -28,15 +26,13 @@ var Analyzer = &analysis.Analyzer{ } // SSA provides SSA-form intermediate representation for all the -// non-blank source functions in the current package. +// source functions in the current package. type SSA struct { Pkg *ssa.Package SrcFuncs []*ssa.Function } func run(pass *analysis.Pass) (interface{}, error) { - // Plundered from ssautil.BuildPackage. - // We must create a new Program for each Package because the // analysis API provides no place to hang a Program shared by // all Packages. Consequently, SSA Packages and Functions do not @@ -53,20 +49,10 @@ func run(pass *analysis.Pass) (interface{}, error) { prog := ssa.NewProgram(pass.Fset, mode) - // Create SSA packages for all imports. - // Order is not significant. - created := make(map[*types.Package]bool) - var createAll func(pkgs []*types.Package) - createAll = func(pkgs []*types.Package) { - for _, p := range pkgs { - if !created[p] { - created[p] = true - prog.CreatePackage(p, nil, nil, true) - createAll(p.Imports()) - } - } + // Create SSA packages for direct imports. + for _, p := range pass.Pkg.Imports() { + prog.CreatePackage(p, nil, nil, true) } - createAll(pass.Pkg.Imports()) // Create and build the primary package. ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false) @@ -78,16 +64,6 @@ func run(pass *analysis.Pass) (interface{}, error) { for _, f := range pass.Files { for _, decl := range f.Decls { if fdecl, ok := decl.(*ast.FuncDecl); ok { - - // SSA will not build a Function - // for a FuncDecl named blank. - // That's arguably too strict but - // relaxing it would break uniqueness of - // names of package members. - if fdecl.Name.Name == "_" { - continue - } - // (init functions have distinct Func // objects named "init" and distinct // ssa.Functions named "init#1", ...) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go b/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go index a2a4a89b3..55bdad78b 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go @@ -40,7 +40,7 @@ func runBuildTag(pass *analysis.Pass) (interface{}, error) { } for _, name := range pass.IgnoredFiles { if strings.HasSuffix(name, ".go") { - f, err := parser.ParseFile(pass.Fset, name, nil, parser.ParseComments) + f, err := parser.ParseFile(pass.Fset, name, nil, parser.ParseComments|parser.SkipObjectResolution) if err != nil { // Not valid Go source code - not our job to diagnose, so ignore. return nil, nil diff --git a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index afff0d82d..4e8643975 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -19,6 +19,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" ) const debug = false @@ -64,7 +65,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t // Is this a C.f() call? var name string - if sel, ok := analysisutil.Unparen(call.Fun).(*ast.SelectorExpr); ok { + if sel, ok := astutil.Unparen(call.Fun).(*ast.SelectorExpr); ok { if id, ok := sel.X.(*ast.Ident); ok && id.Name == "C" { name = sel.Sel.Name } @@ -180,7 +181,7 @@ func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*a // If f is a cgo-generated file, Position reports // the original file, honoring //line directives. filename := fset.Position(raw.Pos()).Filename - f, err := parser.ParseFile(fset, filename, nil, parser.Mode(0)) + f, err := parser.ParseFile(fset, filename, nil, parser.SkipObjectResolution) if err != nil { return nil, nil, fmt.Errorf("can't parse raw cgo file: %v", err) } @@ -271,6 +272,7 @@ func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*a Sizes: sizes, Error: func(error) {}, // ignore errors (e.g. unused import) } + setGoVersion(tc, pkg) // It's tempting to record the new types in the // existing pass.TypesInfo, but we don't own it. diff --git a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go new file mode 100644 index 000000000..06b54946d --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go120.go @@ -0,0 +1,13 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.21 + +package cgocall + +import "go/types" + +func setGoVersion(tc *types.Config, pkg *types.Package) { + // no types.Package.GoVersion until Go 1.21 +} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go new file mode 100644 index 000000000..2a3e1fad2 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall_go121.go @@ -0,0 +1,13 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.21 + +package cgocall + +import "go/types" + +func setGoVersion(tc *types.Config, pkg *types.Package) { + tc.GoVersion = pkg.GoVersion() +} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go b/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go index 20fb70806..847063bb3 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go @@ -37,7 +37,7 @@ should be replaced by: var Analyzer = &analysis.Analyzer{ Name: "composites", Doc: Doc, - URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/composites", + URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/composite", Requires: []*analysis.Analyzer{inspect.Analyzer}, RunDespiteErrors: true, Run: run, @@ -72,7 +72,7 @@ func run(pass *analysis.Pass) (interface{}, error) { } var structuralTypes []types.Type switch typ := typ.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: terms, err := typeparams.StructuralTerms(typ) if err != nil { return // invalid type @@ -163,7 +163,7 @@ func isLocalType(pass *analysis.Pass, typ types.Type) bool { case *types.Named: // names in package foo are local to foo_test too return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test") - case *typeparams.TypeParam: + case *types.TypeParam: return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test") } return false diff --git a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go index b3ca8ada4..6cbbc7e81 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/internal/typeparams" ) @@ -223,6 +224,8 @@ func (path typePath) String() string { } func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath { + x = astutil.Unparen(x) // ignore parens on rhs + if _, ok := x.(*ast.CompositeLit); ok { return nil } @@ -231,7 +234,7 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath { return nil } if star, ok := x.(*ast.StarExpr); ok { - if _, ok := star.X.(*ast.CallExpr); ok { + if _, ok := astutil.Unparen(star.X).(*ast.CallExpr); ok { // A call may return a pointer to a zero value. return nil } @@ -242,29 +245,23 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath { // lockPath returns a typePath describing the location of a lock value // contained in typ. If there is no contained lock, it returns nil. // -// The seenTParams map is used to short-circuit infinite recursion via type -// parameters. -func lockPath(tpkg *types.Package, typ types.Type, seenTParams map[*typeparams.TypeParam]bool) typePath { - if typ == nil { +// The seen map is used to short-circuit infinite recursion due to type cycles. +func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typePath { + if typ == nil || seen[typ] { return nil } + if seen == nil { + seen = make(map[types.Type]bool) + } + seen[typ] = true - if tpar, ok := typ.(*typeparams.TypeParam); ok { - if seenTParams == nil { - // Lazily allocate seenTParams, since the common case will not involve - // any type parameters. - seenTParams = make(map[*typeparams.TypeParam]bool) - } - if seenTParams[tpar] { - return nil - } - seenTParams[tpar] = true + if tpar, ok := typ.(*types.TypeParam); ok { terms, err := typeparams.StructuralTerms(tpar) if err != nil { return nil // invalid type } for _, term := range terms { - subpath := lockPath(tpkg, term.Type(), seenTParams) + subpath := lockPath(tpkg, term.Type(), seen) if len(subpath) > 0 { if term.Tilde() { // Prepend a tilde to our lock path entry to clarify the resulting @@ -298,7 +295,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seenTParams map[*typeparams.T ttyp, ok := typ.Underlying().(*types.Tuple) if ok { for i := 0; i < ttyp.Len(); i++ { - subpath := lockPath(tpkg, ttyp.At(i).Type(), seenTParams) + subpath := lockPath(tpkg, ttyp.At(i).Type(), seen) if subpath != nil { return append(subpath, typ.String()) } @@ -323,16 +320,14 @@ func lockPath(tpkg *types.Package, typ types.Type, seenTParams map[*typeparams.T // In go1.10, sync.noCopy did not implement Locker. // (The Unlock method was added only in CL 121876.) // TODO(adonovan): remove workaround when we drop go1.10. - if named, ok := typ.(*types.Named); ok && - named.Obj().Name() == "noCopy" && - named.Obj().Pkg().Path() == "sync" { + if analysisutil.IsNamedType(typ, "sync", "noCopy") { return []string{typ.String()} } nfields := styp.NumFields() for i := 0; i < nfields; i++ { ftyp := styp.Field(i).Type() - subpath := lockPath(tpkg, ftyp, seenTParams) + subpath := lockPath(tpkg, ftyp, seen) if subpath != nil { return append(subpath, typ.String()) } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go index afc4fdc85..1a83bddbc 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go @@ -12,6 +12,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" ) @@ -34,6 +35,10 @@ var Analyzer = &analysis.Analyzer{ } func run(pass *analysis.Pass) (interface{}, error) { + if !analysisutil.Imports(pass.Pkg, "reflect") { + return nil, nil // doesn't directly import reflect + } + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -41,11 +46,8 @@ func run(pass *analysis.Pass) (interface{}, error) { } inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) - fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func) - if !ok { - return - } - if fn.FullName() == "reflect.DeepEqual" && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) { + fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func) + if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) { pass.ReportRangef(call, "avoid using reflect.DeepEqual with errors") } }) diff --git a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go index 867fc26fa..7f62ad4c8 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -13,6 +13,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" ) @@ -38,6 +39,10 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + if !analysisutil.Imports(pass.Pkg, "errors") { + return nil, nil // doesn't directly import errors + } + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -46,15 +51,12 @@ func run(pass *analysis.Pass) (interface{}, error) { inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) fn := typeutil.StaticCallee(pass.TypesInfo, call) - if fn == nil { - return // not a static call + if !analysisutil.IsFunctionNamed(fn, "errors", "As") { + return } if len(call.Args) < 2 { return // not enough arguments, e.g. called with return values of another function } - if fn.FullName() != "errors.As" { - return - } if err := checkAsTarget(pass, call.Args[1]); err != nil { pass.ReportRangef(call, "%v", err) } @@ -64,9 +66,6 @@ func run(pass *analysis.Pass) (interface{}, error) { var errorType = types.Universe.Lookup("error").Type() -// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error, -// or is the empty interface. - // checkAsTarget reports an error if the second argument to errors.As is invalid. func checkAsTarget(pass *analysis.Pass, e ast.Expr) error { t := pass.TypesInfo.Types[e].Type diff --git a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go index 61c3b764f..c6b6c81b4 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go @@ -116,7 +116,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool { if res.Len() != 2 { return false // the function called does not return two values. } - if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") { + if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !analysisutil.IsNamedType(ptr.Elem(), "net/http", "Response") { return false // the first return type is not *http.Response. } @@ -131,11 +131,11 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool { return ok && id.Name == "http" // function in net/http package. } - if isNamedType(typ, "net/http", "Client") { + if analysisutil.IsNamedType(typ, "net/http", "Client") { return true // method on http.Client. } ptr, ok := typ.(*types.Pointer) - return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. + return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. } // restOfBlock, given a traversal stack, finds the innermost containing @@ -171,13 +171,3 @@ func rootIdent(n ast.Node) *ast.Ident { return nil } } - -// isNamedType reports whether t is the named type path.name. -func isNamedType(t types.Type, path, name string) bool { - n, ok := t.(*types.Named) - if !ok { - return false - } - obj := n.Obj() - return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path -} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go index b35f62dc7..12507f996 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/ifaceassert/parameterized.go @@ -67,7 +67,7 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { // of a generic function type (or an interface method) that is // part of the type we're testing. We don't care about these type // parameters. - // Similarly, the receiver of a method may declare (rather then + // Similarly, the receiver of a method may declare (rather than // use) type parameters, we don't care about those either. // Thus, we only need to look at the input and result parameters. return w.isParameterized(t.Params()) || w.isParameterized(t.Results()) @@ -95,14 +95,14 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { return w.isParameterized(t.Elem()) case *types.Named: - list := typeparams.NamedTypeArgs(t) + list := t.TypeArgs() for i, n := 0, list.Len(); i < n; i++ { if w.isParameterized(list.At(i)) { return true } } - case *typeparams.TypeParam: + case *types.TypeParam: return true default: diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go index ac37e4784..3f01b3b55 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go @@ -12,7 +12,9 @@ import ( "go/printer" "go/token" "go/types" - "io/ioutil" + "os" + + "golang.org/x/tools/internal/analysisinternal" ) // Format returns a string representation of the expression. @@ -55,21 +57,10 @@ func HasSideEffects(info *types.Info, e ast.Expr) bool { return !safe } -// Unparen returns e with any enclosing parentheses stripped. -func Unparen(e ast.Expr) ast.Expr { - for { - p, ok := e.(*ast.ParenExpr) - if !ok { - return e - } - e = p.X - } -} - // ReadFile reads a file and adds it to the FileSet // so that we can report errors against it using lineStart. func ReadFile(fset *token.FileSet, filename string) ([]byte, *token.File, error) { - content, err := ioutil.ReadFile(filename) + content, err := os.ReadFile(filename) if err != nil { return nil, nil, err } @@ -118,3 +109,48 @@ func Imports(pkg *types.Package, path string) bool { } return false } + +// IsNamedType reports whether t is the named type with the given package path +// and one of the given names. +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsNamedType(t types.Type, pkgPath string, names ...string) bool { + n, ok := t.(*types.Named) + if !ok { + return false + } + obj := n.Obj() + if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath { + return false + } + name := obj.Name() + for _, n := range names { + if name == n { + return true + } + } + return false +} + +// IsFunctionNamed reports whether f is a top-level function defined in the +// given package and has one of the given names. +// It returns false if f is nil or a method. +func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool { + if f == nil { + return false + } + if f.Pkg() == nil || f.Pkg().Path() != pkgPath { + return false + } + if f.Type().(*types.Signature).Recv() != nil { + return false + } + for _, n := range names { + if f.Name() == n { + return true + } + } + return false +} + +var MustExtractDoc = analysisinternal.MustExtractDoc diff --git a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go index dc544df1b..c95b1c1c9 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go @@ -14,8 +14,12 @@ // in such a way (e.g. with go or defer) that it may outlive the loop // iteration and possibly observe the wrong value of the variable. // +// Note: An iteration variable can only outlive a loop iteration in Go versions <=1.21. +// In Go 1.22 and later, the loop variable lifetimes changed to create a new +// iteration variable per loop iteration. (See go.dev/issue/60078.) +// // In this example, all the deferred functions run after the loop has -// completed, so all observe the final value of v. +// completed, so all observe the final value of v [ 0 { + if tparams := fn.Type.TypeParams; tparams != nil && len(tparams.List) > 0 { pass.Reportf(fn.Pos(), "%s should not have type params", fnName) } @@ -466,7 +459,7 @@ func checkTest(pass *analysis.Pass, fn *ast.FuncDecl, prefix string) { return } - if tparams := typeparams.ForFuncType(fn.Type); tparams != nil && len(tparams.List) > 0 { + if tparams := fn.Type.TypeParams; tparams != nil && len(tparams.List) > 0 { // Note: cmd/go/internal/load also errors about TestXXX and BenchmarkXXX functions with type parameters. // We have currently decided to also warn before compilation/package loading. This can help users in IDEs. // TODO(adonovan): use ReportRangef(tparams). diff --git a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go index f9b79078c..eb84502bd 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go @@ -24,13 +24,6 @@ import ( const badFormat = "2006-02-01" const goodFormat = "2006-01-02" -const Doc = `check for calls of (time.Time).Format or time.Parse with 2006-02-01 - -The timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm) -format. Internationally, "yyyy-dd-mm" does not occur in common calendar date -standards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended. -` - //go:embed doc.go var doc string @@ -43,6 +36,11 @@ var Analyzer = &analysis.Analyzer{ } func run(pass *analysis.Pass) (interface{}, error) { + // Note: (time.Time).Format is a method and can be a typeutil.Callee + // without directly importing "time". So we cannot just skip this package + // when !analysisutil.Imports(pass.Pkg, "time"). + // TODO(taking): Consider using a prepass to collect typeutil.Callees. + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -90,29 +88,16 @@ func run(pass *analysis.Pass) (interface{}, error) { } func isTimeDotFormat(f *types.Func) bool { - if f.Name() != "Format" || f.Pkg().Path() != "time" { - return false - } - sig, ok := f.Type().(*types.Signature) - if !ok { + if f.Name() != "Format" || f.Pkg() == nil || f.Pkg().Path() != "time" { return false } // Verify that the receiver is time.Time. - recv := sig.Recv() - if recv == nil { - return false - } - named, ok := recv.Type().(*types.Named) - return ok && named.Obj().Name() == "Time" + recv := f.Type().(*types.Signature).Recv() + return recv != nil && analysisutil.IsNamedType(recv.Type(), "time", "Time") } func isTimeDotParse(f *types.Func) bool { - if f.Name() != "Parse" || f.Pkg().Path() != "time" { - return false - } - // Verify that there is no receiver. - sig, ok := f.Type().(*types.Signature) - return ok && sig.Recv() == nil + return analysisutil.IsFunctionNamed(f, "time", "Parse") } // badFormatAt return the start of a bad format in e or -1 if no bad format is found. diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go index 28f552df8..f4e73528b 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go @@ -14,7 +14,6 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" - "golang.org/x/tools/internal/typeparams" ) //go:embed doc.go @@ -36,6 +35,12 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + // Note: (*"encoding/json".Decoder).Decode, (* "encoding/gob".Decoder).Decode + // and (* "encoding/xml".Decoder).Decode are methods and can be a typeutil.Callee + // without directly importing their packages. So we cannot just skip this package + // when !analysisutil.Imports(pass.Pkg, "encoding/..."). + // TODO(taking): Consider using a prepass to collect typeutil.Callees. + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -50,6 +55,7 @@ func run(pass *analysis.Pass) (interface{}, error) { // Classify the callee (without allocating memory). argidx := -1 + recv := fn.Type().(*types.Signature).Recv() if fn.Name() == "Unmarshal" && recv == nil { // "encoding/json".Unmarshal @@ -85,7 +91,7 @@ func run(pass *analysis.Pass) (interface{}, error) { t := pass.TypesInfo.Types[call.Args[argidx]].Type switch t.Underlying().(type) { - case *types.Pointer, *types.Interface, *typeparams.TypeParam: + case *types.Pointer, *types.Interface, *types.TypeParam: return } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go index 524fd0463..de10804cb 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/doc.go @@ -13,5 +13,5 @@ // to convert integers to pointers. A conversion from uintptr to // unsafe.Pointer is invalid if it implies that there is a uintptr-typed // word in memory that holds a pointer value, because that word will be -// invisible to stack copying and to the garbage collector.` +// invisible to stack copying and to the garbage collector. package unsafeptr diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go index b1a32f249..32e71ef97 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go @@ -15,17 +15,10 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" ) -const Doc = `check for invalid conversions of uintptr to unsafe.Pointer - -The unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer -to convert integers to pointers. A conversion from uintptr to -unsafe.Pointer is invalid if it implies that there is a uintptr-typed -word in memory that holds a pointer value, because that word will be -invisible to stack copying and to the garbage collector.` - //go:embed doc.go var doc string @@ -76,7 +69,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { // Check unsafe.Pointer safety rules according to // https://golang.org/pkg/unsafe/#Pointer. - switch x := analysisutil.Unparen(x).(type) { + switch x := astutil.Unparen(x).(type) { case *ast.SelectorExpr: // "(6) Conversion of a reflect.SliceHeader or // reflect.StringHeader Data field to or from Pointer." @@ -112,8 +105,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { } switch sel.Sel.Name { case "Pointer", "UnsafeAddr": - t, ok := info.Types[sel.X].Type.(*types.Named) - if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" { + if analysisutil.IsNamedType(info.Types[sel.X].Type, "reflect", "Value") { return true } } @@ -126,7 +118,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { // isSafeArith reports whether x is a pointer arithmetic expression that is safe // to convert to unsafe.Pointer. func isSafeArith(info *types.Info, x ast.Expr) bool { - switch x := analysisutil.Unparen(x).(type) { + switch x := astutil.Unparen(x).(type) { case *ast.CallExpr: // Base case: initial conversion from unsafe.Pointer to uintptr. return len(x.Args) == 1 && @@ -161,13 +153,5 @@ func hasBasicType(info *types.Info, x ast.Expr, kind types.BasicKind) bool { // isReflectHeader reports whether t is reflect.SliceHeader or reflect.StringHeader. func isReflectHeader(t types.Type) bool { - if named, ok := t.(*types.Named); ok { - if obj := named.Obj(); obj.Pkg() != nil && obj.Pkg().Path() == "reflect" { - switch obj.Name() { - case "SliceHeader", "StringHeader": - return true - } - } - } - return false + return analysisutil.IsNamedType(t, "reflect", "SliceHeader", "StringHeader") } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go index 0a713ca0d..a1bf4cf94 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/doc.go @@ -9,9 +9,11 @@ // // unusedresult: check for unused results of calls to some functions // -// Some functions like fmt.Errorf return a result and have no side effects, -// so it is always a mistake to discard the result. This analyzer reports -// calls to certain functions in which the result of the call is ignored. +// Some functions like fmt.Errorf return a result and have no side +// effects, so it is always a mistake to discard the result. Other +// functions may return an error that must not be ignored, or a cleanup +// operation that must be called. This analyzer reports calls to +// functions like these when the result of the call is ignored. // // The set of functions may be controlled using flags. package unusedresult diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go index 051bc7c81..76f42b052 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go +++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go @@ -3,9 +3,16 @@ // license that can be found in the LICENSE file. // Package unusedresult defines an analyzer that checks for unused -// results of calls to certain pure functions. +// results of calls to certain functions. package unusedresult +// It is tempting to make this analysis inductive: for each function +// that tail-calls one of the functions that we check, check those +// functions too. However, just because you must use the result of +// fmt.Sprintf doesn't mean you need to use the result of every +// function that returns a formatted string: it may have other results +// and effects. + import ( _ "embed" "go/ast" @@ -17,18 +24,11 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/inspector" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/go/types/typeutil" ) -const Doc = `check for unused results of calls to some functions - -Some functions like fmt.Errorf return a result and have no side effects, -so it is always a mistake to discard the result. This analyzer reports -calls to certain functions in which the result of the call is ignored. - -The set of functions may be controlled using flags.` - //go:embed doc.go var doc string @@ -56,16 +56,28 @@ func init() { // ignoringTheErrorWouldBeVeryBad() // oops // - // Also, it is tempting to make this analysis modular: one - // could export a "mustUseResult" fact for each function that - // tail-calls one of the functions that we check, and check - // those functions too. - // - // However, just because you must use the result of - // fmt.Sprintf doesn't mean you need to use the result of - // every function that returns a formatted string: - // it may have other results and effects. - funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse,context.WithValue,context.WithCancel,context.WithDeadline,context.WithTimeout") + // List standard library functions here. + // The context.With{Cancel,Deadline,Timeout} entries are + // effectively redundant wrt the lostcancel analyzer. + funcs = stringSetFlag{ + "context.WithCancel": true, + "context.WithDeadline": true, + "context.WithTimeout": true, + "context.WithValue": true, + "errors.New": true, + "fmt.Errorf": true, + "fmt.Sprint": true, + "fmt.Sprintf": true, + "slices.Clip": true, + "slices.Compact": true, + "slices.CompactFunc": true, + "slices.Delete": true, + "slices.DeleteFunc": true, + "slices.Grow": true, + "slices.Insert": true, + "slices.Replace": true, + "sort.Reverse": true, + } Analyzer.Flags.Var(&funcs, "funcs", "comma-separated list of functions whose results must be used") @@ -77,49 +89,41 @@ func init() { func run(pass *analysis.Pass) (interface{}, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + // Split functions into (pkg, name) pairs to save allocation later. + pkgFuncs := make(map[[2]string]bool, len(funcs)) + for s := range funcs { + if i := strings.LastIndexByte(s, '.'); i > 0 { + pkgFuncs[[2]string{s[:i], s[i+1:]}] = true + } + } + nodeFilter := []ast.Node{ (*ast.ExprStmt)(nil), } inspect.Preorder(nodeFilter, func(n ast.Node) { - call, ok := analysisutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) + call, ok := astutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) if !ok { return // not a call statement } - fun := analysisutil.Unparen(call.Fun) - - if pass.TypesInfo.Types[fun].IsType() { - return // a conversion, not a call - } - x, _, _, _ := typeparams.UnpackIndexExpr(fun) - if x != nil { - fun = x // If this is generic function or method call, skip the instantiation arguments - } - - selector, ok := fun.(*ast.SelectorExpr) + // Call to function or method? + fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func) if !ok { - return // neither a method call nor a qualified ident + return // e.g. var or builtin } - - sel, ok := pass.TypesInfo.Selections[selector] - if ok && sel.Kind() == types.MethodVal { + if sig := fn.Type().(*types.Signature); sig.Recv() != nil { // method (e.g. foo.String()) - obj := sel.Obj().(*types.Func) - sig := sel.Type().(*types.Signature) if types.Identical(sig, sigNoArgsStringResult) { - if stringMethods[obj.Name()] { + if stringMethods[fn.Name()] { pass.Reportf(call.Lparen, "result of (%s).%s call not used", - sig.Recv().Type(), obj.Name()) + sig.Recv().Type(), fn.Name()) } } - } else if !ok { - // package-qualified function (e.g. fmt.Errorf) - obj := pass.TypesInfo.Uses[selector.Sel] - if obj, ok := obj.(*types.Func); ok { - qname := obj.Pkg().Path() + "." + obj.Name() - if funcs[qname] { - pass.Reportf(call.Lparen, "result of %v call not used", qname) - } + } else { + // package-level function (e.g. fmt.Errorf) + if pkgFuncs[[2]string{fn.Pkg().Path(), fn.Name()}] { + pass.Reportf(call.Lparen, "result of %s.%s call not used", + fn.Pkg().Path(), fn.Name()) } } }) diff --git a/vendor/golang.org/x/tools/go/analysis/validate.go b/vendor/golang.org/x/tools/go/analysis/validate.go index 9da5692af..4f2c40456 100644 --- a/vendor/golang.org/x/tools/go/analysis/validate.go +++ b/vendor/golang.org/x/tools/go/analysis/validate.go @@ -19,6 +19,8 @@ import ( // that the Requires graph is acyclic; // that analyzer fact types are unique; // that each fact type is a pointer. +// +// Analyzer names need not be unique, though this may be confusing. func Validate(analyzers []*Analyzer) error { // Map each fact type to its sole generating analyzer. factTypes := make(map[reflect.Type]*Analyzer) diff --git a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go index 9fa5aa192..2c4c4e232 100644 --- a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go +++ b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go @@ -11,8 +11,6 @@ import ( "go/ast" "go/token" "sort" - - "golang.org/x/tools/internal/typeparams" ) // PathEnclosingInterval returns the node that encloses the source @@ -322,7 +320,7 @@ func childrenOf(n ast.Node) []ast.Node { children = append(children, n.Recv) } children = append(children, n.Name) - if tparams := typeparams.ForFuncType(n.Type); tparams != nil { + if tparams := n.Type.TypeParams; tparams != nil { children = append(children, tparams) } if n.Type.Params != nil { @@ -377,7 +375,7 @@ func childrenOf(n ast.Node) []ast.Node { tok(n.Lbrack, len("[")), tok(n.Rbrack, len("]"))) - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: children = append(children, tok(n.Lbrack, len("[")), tok(n.Rbrack, len("]"))) @@ -588,7 +586,7 @@ func NodeDescription(n ast.Node) string { return "decrement statement" case *ast.IndexExpr: return "index expression" - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: return "index list expression" case *ast.InterfaceType: return "interface type" diff --git a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go index f430b21b9..58934f766 100644 --- a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go +++ b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go @@ -9,8 +9,6 @@ import ( "go/ast" "reflect" "sort" - - "golang.org/x/tools/internal/typeparams" ) // An ApplyFunc is invoked by Apply for each node n, even if n is nil, @@ -252,7 +250,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. a.apply(n, "X", nil, n.X) a.apply(n, "Index", nil, n.Index) - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: a.apply(n, "X", nil, n.X) a.applyList(n, "Indices") @@ -293,7 +291,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. a.apply(n, "Fields", nil, n.Fields) case *ast.FuncType: - if tparams := typeparams.ForFuncType(n); tparams != nil { + if tparams := n.TypeParams; tparams != nil { a.apply(n, "TypeParams", nil, tparams) } a.apply(n, "Params", nil, n.Params) @@ -408,7 +406,7 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast. case *ast.TypeSpec: a.apply(n, "Doc", nil, n.Doc) a.apply(n, "Name", nil, n.Name) - if tparams := typeparams.ForTypeSpec(n); tparams != nil { + if tparams := n.TypeParams; tparams != nil { a.apply(n, "TypeParams", nil, tparams) } a.apply(n, "Type", nil, n.Type) diff --git a/vendor/golang.org/x/tools/go/ast/inspector/inspector.go b/vendor/golang.org/x/tools/go/ast/inspector/inspector.go index 3fbfebf36..1fc1de0bd 100644 --- a/vendor/golang.org/x/tools/go/ast/inspector/inspector.go +++ b/vendor/golang.org/x/tools/go/ast/inspector/inspector.go @@ -64,8 +64,9 @@ type event struct { // depth-first order. It calls f(n) for each node n before it visits // n's children. // +// The complete traversal sequence is determined by ast.Inspect. // The types argument, if non-empty, enables type-based filtering of -// events. The function f if is called only for nodes whose type +// events. The function f is called only for nodes whose type // matches an element of the types slice. func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // Because it avoids postorder calls to f, and the pruning @@ -97,6 +98,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // of the non-nil children of the node, followed by a call of // f(n, false). // +// The complete traversal sequence is determined by ast.Inspect. // The types argument, if non-empty, enables type-based filtering of // events. The function f if is called only for nodes whose type // matches an element of the types slice. diff --git a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go index 703c81395..2a872f89d 100644 --- a/vendor/golang.org/x/tools/go/ast/inspector/typeof.go +++ b/vendor/golang.org/x/tools/go/ast/inspector/typeof.go @@ -12,8 +12,6 @@ package inspector import ( "go/ast" "math" - - "golang.org/x/tools/internal/typeparams" ) const ( @@ -171,7 +169,7 @@ func typeOf(n ast.Node) uint64 { return 1 << nIncDecStmt case *ast.IndexExpr: return 1 << nIndexExpr - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: return 1 << nIndexListExpr case *ast.InterfaceType: return 1 << nInterfaceType diff --git a/vendor/golang.org/x/tools/go/buildutil/fakecontext.go b/vendor/golang.org/x/tools/go/buildutil/fakecontext.go index 15025f645..763d18809 100644 --- a/vendor/golang.org/x/tools/go/buildutil/fakecontext.go +++ b/vendor/golang.org/x/tools/go/buildutil/fakecontext.go @@ -8,7 +8,6 @@ import ( "fmt" "go/build" "io" - "io/ioutil" "os" "path" "path/filepath" @@ -76,7 +75,7 @@ func FakeContext(pkgs map[string]map[string]string) *build.Context { if !ok { return nil, fmt.Errorf("file not found: %s", filename) } - return ioutil.NopCloser(strings.NewReader(content)), nil + return io.NopCloser(strings.NewReader(content)), nil } ctxt.IsAbsPath = func(path string) bool { path = filepath.ToSlash(path) diff --git a/vendor/golang.org/x/tools/go/buildutil/overlay.go b/vendor/golang.org/x/tools/go/buildutil/overlay.go index bdbfd9314..7e371658d 100644 --- a/vendor/golang.org/x/tools/go/buildutil/overlay.go +++ b/vendor/golang.org/x/tools/go/buildutil/overlay.go @@ -10,7 +10,6 @@ import ( "fmt" "go/build" "io" - "io/ioutil" "path/filepath" "strconv" "strings" @@ -33,7 +32,7 @@ func OverlayContext(orig *build.Context, overlay map[string][]byte) *build.Conte // TODO(dominikh): Implement IsDir, HasSubdir and ReadDir rc := func(data []byte) (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewBuffer(data)), nil + return io.NopCloser(bytes.NewBuffer(data)), nil } copy := *orig // make a copy diff --git a/vendor/golang.org/x/tools/go/callgraph/callgraph.go b/vendor/golang.org/x/tools/go/callgraph/callgraph.go index 905623753..a1b0ca5da 100644 --- a/vendor/golang.org/x/tools/go/callgraph/callgraph.go +++ b/vendor/golang.org/x/tools/go/callgraph/callgraph.go @@ -64,6 +64,7 @@ func New(root *ssa.Function) *Graph { } // CreateNode returns the Node for fn, creating it if not present. +// The root node may have fn=nil. func (g *Graph) CreateNode(fn *ssa.Function) *Node { n, ok := g.Nodes[fn] if !ok { diff --git a/vendor/golang.org/x/tools/go/callgraph/vta/graph.go b/vendor/golang.org/x/tools/go/callgraph/vta/graph.go index 2537123f4..4b5a65b33 100644 --- a/vendor/golang.org/x/tools/go/callgraph/vta/graph.go +++ b/vendor/golang.org/x/tools/go/callgraph/vta/graph.go @@ -106,12 +106,12 @@ type field struct { } func (f field) Type() types.Type { - s := f.StructType.Underlying().(*types.Struct) + s := typeparams.CoreType(f.StructType).(*types.Struct) return s.Field(f.index).Type() } func (f field) String() string { - s := f.StructType.Underlying().(*types.Struct) + s := typeparams.CoreType(f.StructType).(*types.Struct) return fmt.Sprintf("Field(%v:%s)", f.StructType, s.Field(f.index).Name()) } @@ -434,7 +434,7 @@ func (b *builder) field(f *ssa.Field) { } func (b *builder) fieldAddr(f *ssa.FieldAddr) { - t := f.X.Type().Underlying().(*types.Pointer).Elem() + t := typeparams.CoreType(f.X.Type()).(*types.Pointer).Elem() // Since we are getting pointer to a field, make a bidirectional edge. fnode := field{StructType: t, index: f.Field} @@ -497,7 +497,13 @@ func (b *builder) lookup(l *ssa.Lookup) { // No interesting flows for string lookups. return } - b.addInFlowAliasEdges(b.nodeFromVal(l), mapValue{typ: t.Elem()}) + + if !l.CommaOk { + b.addInFlowAliasEdges(b.nodeFromVal(l), mapValue{typ: t.Elem()}) + } else { + i := indexedLocal{val: l, typ: t.Elem(), index: 0} + b.addInFlowAliasEdges(i, mapValue{typ: t.Elem()}) + } } // mapUpdate handles map update commands m[b] = a where m is of type @@ -661,14 +667,14 @@ func addReturnFlows(b *builder, r *ssa.Return, site ssa.Value) { func (b *builder) multiconvert(c *ssa.MultiConvert) { // TODO(zpavlinovic): decide what to do on MultiConvert long term. // TODO(zpavlinovic): add unit tests. - typeSetOf := func(typ types.Type) []*typeparams.Term { + typeSetOf := func(typ types.Type) []*types.Term { // This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on. - var terms []*typeparams.Term + var terms []*types.Term var err error switch typ := typ.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: terms, err = typeparams.StructuralTerms(typ) - case *typeparams.Union: + case *types.Union: terms, err = typeparams.UnionTermSet(typ) case *types.Interface: terms, err = typeparams.InterfaceTermSet(typ) @@ -676,7 +682,7 @@ func (b *builder) multiconvert(c *ssa.MultiConvert) { // Common case. // Specializing the len=1 case to avoid a slice // had no measurable space/time benefit. - terms = []*typeparams.Term{typeparams.NewTerm(false, typ)} + terms = []*types.Term{types.NewTerm(false, typ)} } if err != nil { diff --git a/vendor/golang.org/x/tools/go/callgraph/vta/internal/trie/builder.go b/vendor/golang.org/x/tools/go/callgraph/vta/internal/trie/builder.go index 11ff59b1b..08f14c679 100644 --- a/vendor/golang.org/x/tools/go/callgraph/vta/internal/trie/builder.go +++ b/vendor/golang.org/x/tools/go/callgraph/vta/internal/trie/builder.go @@ -378,7 +378,7 @@ func (b *Builder) merge(c Collision, lhs, rhs node) node { } } - // Last remaining case is branch branch merging. + // Last remaining case is branch merging. // For brevity, we adopt the Okasaki and Gill naming conventions // for branching and prefixes. s, t := lhs.(*branch), rhs.(*branch) @@ -472,7 +472,7 @@ func (b *Builder) intersect(c Collision, l, r node) node { // fallthrough } } - // Last remaining case is branch branch intersection. + // Last remaining case is branch intersection. s, t := l.(*branch), r.(*branch) p, m := s.prefix, s.branching q, n := t.prefix, t.branching diff --git a/vendor/golang.org/x/tools/go/callgraph/vta/utils.go b/vendor/golang.org/x/tools/go/callgraph/vta/utils.go index d1831983a..3471aae3a 100644 --- a/vendor/golang.org/x/tools/go/callgraph/vta/utils.go +++ b/vendor/golang.org/x/tools/go/callgraph/vta/utils.go @@ -123,7 +123,14 @@ func functionUnderPtr(t types.Type) types.Type { func sliceArrayElem(t types.Type) types.Type { switch u := t.Underlying().(type) { case *types.Pointer: - return u.Elem().Underlying().(*types.Array).Elem() + switch e := u.Elem().Underlying().(type) { + case *types.Array: + return e.Elem() + case *types.Interface: + return sliceArrayElem(e) // e is a type param with matching element types. + default: + panic(t) + } case *types.Array: return u.Elem() case *types.Slice: diff --git a/vendor/golang.org/x/tools/go/callgraph/vta/vta.go b/vendor/golang.org/x/tools/go/callgraph/vta/vta.go index 583936003..2303fcfa0 100644 --- a/vendor/golang.org/x/tools/go/callgraph/vta/vta.go +++ b/vendor/golang.org/x/tools/go/callgraph/vta/vta.go @@ -154,6 +154,9 @@ func propFunc(p propType, c ssa.CallInstruction, cache methodCache) []*ssa.Funct // ssa.Program.MethodSets and ssa.Program.MethodValue // APIs. The cache is used to speed up querying of // methods of a type as the mentioned APIs are expensive. +// +// TODO(adonovan): Program.MethodValue already does this kind of +// caching. Is this really necessary? type methodCache map[types.Type]map[string][]*ssa.Function // methods returns methods of a type `t` named `name`. First consults diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go index 165ede0f8..03543bd4b 100644 --- a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go +++ b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go @@ -128,15 +128,14 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, // (from "version"). Select appropriate importer. if len(data) > 0 { switch data[0] { - case 'i': - _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) - return pkg, err + case 'v', 'c', 'd': // binary, till go1.10 + return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0]) - case 'v', 'c', 'd': - _, pkg, err := gcimporter.BImportData(fset, imports, data, path) + case 'i': // indexed, till go1.19 + _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) return pkg, err - case 'u': + case 'u': // unified, from go1.20 _, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path) return pkg, err diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go index 3fce48003..697974bb9 100644 --- a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go +++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go @@ -57,20 +57,18 @@ import ( "go/build" "go/parser" "go/token" - "io/ioutil" "log" "os" + "os/exec" "path/filepath" "regexp" "strings" - - exec "golang.org/x/sys/execabs" ) // ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses // the output and returns the resulting ASTs. func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) { - tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C") + tmpdir, err := os.MkdirTemp("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C") if err != nil { return nil, err } diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go index 7d94bbc1e..b5bb95a63 100644 --- a/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go +++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go @@ -8,7 +8,7 @@ import ( "errors" "fmt" "go/build" - exec "golang.org/x/sys/execabs" + "os/exec" "strings" ) diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go index 18a002f82..333676b7c 100644 --- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go +++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -8,42 +8,46 @@ package packagesdriver import ( "context" "fmt" - "go/types" "strings" "golang.org/x/tools/internal/gocommand" ) -var debug = false - -func GetSizesGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (types.Sizes, error) { +func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (string, string, error) { inv.Verb = "list" inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"} stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv) var goarch, compiler string if rawErr != nil { - if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") { - // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc. + rawErrMsg := rawErr.Error() + if strings.Contains(rawErrMsg, "cannot find main module") || + strings.Contains(rawErrMsg, "go.mod file not found") { + // User's running outside of a module. + // All bets are off. Get GOARCH and guess compiler is gc. // TODO(matloob): Is this a problem in practice? inv.Verb = "env" inv.Args = []string{"GOARCH"} envout, enverr := gocmdRunner.Run(ctx, inv) if enverr != nil { - return nil, enverr + return "", "", enverr } goarch = strings.TrimSpace(envout.String()) compiler = "gc" + } else if friendlyErr != nil { + return "", "", friendlyErr } else { - return nil, friendlyErr + // This should be unreachable, but be defensive + // in case RunRaw's error results are inconsistent. + return "", "", rawErr } } else { fields := strings.Fields(stdout.String()) if len(fields) < 2 { - return nil, fmt.Errorf("could not parse GOARCH and Go compiler in format \" \":\nstdout: <<%s>>\nstderr: <<%s>>", + return "", "", fmt.Errorf("could not parse GOARCH and Go compiler in format \" \":\nstdout: <<%s>>\nstderr: <<%s>>", stdout.String(), stderr.String()) } goarch = fields[0] compiler = fields[1] } - return types.SizesFor(compiler, goarch), nil + return compiler, goarch, nil } diff --git a/vendor/golang.org/x/tools/go/loader/loader.go b/vendor/golang.org/x/tools/go/loader/loader.go index edf62c2cc..013c0f505 100644 --- a/vendor/golang.org/x/tools/go/loader/loader.go +++ b/vendor/golang.org/x/tools/go/loader/loader.go @@ -23,7 +23,7 @@ import ( "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/internal/cgo" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) var ignoreVendor build.ImportMode @@ -1033,13 +1033,14 @@ func (imp *importer) newPackageInfo(path, dir string) *PackageInfo { Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), }, errorFunc: imp.conf.TypeChecker.Error, dir: dir, } - typeparams.InitInstanceInfo(&info.Info) + versions.InitFileVersions(&info.Info) // Copy the types.Config so we can vary it across PackageInfos. tc := imp.conf.TypeChecker diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/vendor/golang.org/x/tools/go/packages/doc.go index da4ab89fe..b2a0b7c6a 100644 --- a/vendor/golang.org/x/tools/go/packages/doc.go +++ b/vendor/golang.org/x/tools/go/packages/doc.go @@ -5,12 +5,32 @@ /* Package packages loads Go packages for inspection and analysis. -The Load function takes as input a list of patterns and return a list of Package -structs describing individual packages matched by those patterns. -The LoadMode controls the amount of detail in the loaded packages. - -Load passes most patterns directly to the underlying build tool, -but all patterns with the prefix "query=", where query is a +The [Load] function takes as input a list of patterns and returns a +list of [Package] values describing individual packages matched by those +patterns. +A [Config] specifies configuration options, the most important of which is +the [LoadMode], which controls the amount of detail in the loaded packages. + +Load passes most patterns directly to the underlying build tool. +The default build tool is the go command. +Its supported patterns are described at +https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns. + +Load may be used in Go projects that use alternative build systems, by +installing an appropriate "driver" program for the build system and +specifying its location in the GOPACKAGESDRIVER environment variable. +For example, +https://github.com/bazelbuild/rules_go/wiki/Editor-and-tool-integration +explains how to use the driver for Bazel. +The driver program is responsible for interpreting patterns in its +preferred notation and reporting information about the packages that +they identify. +(See driverRequest and driverResponse types for the JSON +schema used by the protocol. +Though the protocol is supported, these types are currently unexported; +see #64608 for a proposal to publish them.) + +Regardless of driver, all patterns with the prefix "query=", where query is a non-empty string of letters from [a-z], are reserved and may be interpreted as query operators. @@ -35,7 +55,7 @@ The Package struct provides basic information about the package, including - Imports, a map from source import strings to the Packages they name; - Types, the type information for the package's exported symbols; - Syntax, the parsed syntax trees for the package's source code; and - - TypeInfo, the result of a complete type-check of the package syntax trees. + - TypesInfo, the result of a complete type-check of the package syntax trees. (See the documentation for type Package for the complete list of fields and more detailed descriptions.) @@ -64,7 +84,7 @@ reported about the loaded packages. See the documentation for type LoadMode for details. Most tools should pass their command-line arguments (after any flags) -uninterpreted to the loader, so that the loader can interpret them +uninterpreted to [Load], so that it can interpret them according to the conventions of the underlying build system. See the Example function for typical usage. */ diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go index 7242a0a7d..7db1d1293 100644 --- a/vendor/golang.org/x/tools/go/packages/external.go +++ b/vendor/golang.org/x/tools/go/packages/external.go @@ -12,8 +12,8 @@ import ( "bytes" "encoding/json" "fmt" - exec "golang.org/x/sys/execabs" "os" + "os/exec" "strings" ) diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go index 6bb7168d2..cd375fbc3 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -9,10 +9,9 @@ import ( "context" "encoding/json" "fmt" - "go/types" - "io/ioutil" "log" "os" + "os/exec" "path" "path/filepath" "reflect" @@ -22,7 +21,6 @@ import ( "sync" "unicode" - exec "golang.org/x/sys/execabs" "golang.org/x/tools/go/internal/packagesdriver" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" @@ -153,10 +151,10 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 { sizeswg.Add(1) go func() { - var sizes types.Sizes - sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner) - // types.SizesFor always returns nil or a *types.StdSizes. - response.dr.Sizes, _ = sizes.(*types.StdSizes) + compiler, arch, err := packagesdriver.GetSizesForArgsGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner) + sizeserr = err + response.dr.Compiler = compiler + response.dr.Arch = arch sizeswg.Done() }() } @@ -210,62 +208,6 @@ extractQueries: } } - // Only use go/packages' overlay processing if we're using a Go version - // below 1.16. Otherwise, go list handles it. - if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 { - modifiedPkgs, needPkgs, err := state.processGolistOverlay(response) - if err != nil { - return nil, err - } - - var containsCandidates []string - if len(containFiles) > 0 { - containsCandidates = append(containsCandidates, modifiedPkgs...) - containsCandidates = append(containsCandidates, needPkgs...) - } - if err := state.addNeededOverlayPackages(response, needPkgs); err != nil { - return nil, err - } - // Check candidate packages for containFiles. - if len(containFiles) > 0 { - for _, id := range containsCandidates { - pkg, ok := response.seenPackages[id] - if !ok { - response.addPackage(&Package{ - ID: id, - Errors: []Error{{ - Kind: ListError, - Msg: fmt.Sprintf("package %s expected but not seen", id), - }}, - }) - continue - } - for _, f := range containFiles { - for _, g := range pkg.GoFiles { - if sameFile(f, g) { - response.addRoot(id) - } - } - } - } - } - // Add root for any package that matches a pattern. This applies only to - // packages that are modified by overlays, since they are not added as - // roots automatically. - for _, pattern := range restPatterns { - match := matchPattern(pattern) - for _, pkgID := range modifiedPkgs { - pkg, ok := response.seenPackages[pkgID] - if !ok { - continue - } - if match(pkg.PkgPath) { - response.addRoot(pkg.ID) - } - } - } - } - sizeswg.Wait() if sizeserr != nil { return nil, sizeserr @@ -273,24 +215,6 @@ extractQueries: return response.dr, nil } -func (state *golistState) addNeededOverlayPackages(response *responseDeduper, pkgs []string) error { - if len(pkgs) == 0 { - return nil - } - dr, err := state.createDriverResponse(pkgs...) - if err != nil { - return err - } - for _, pkg := range dr.Packages { - response.addPackage(pkg) - } - _, needPkgs, err := state.processGolistOverlay(response) - if err != nil { - return err - } - return state.addNeededOverlayPackages(response, needPkgs) -} - func (state *golistState) runContainsQueries(response *responseDeduper, queries []string) error { for _, query := range queries { // TODO(matloob): Do only one query per directory. @@ -625,7 +549,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse } if pkg.PkgPath == "unsafe" { - pkg.GoFiles = nil // ignore fake unsafe.go file + pkg.CompiledGoFiles = nil // ignore fake unsafe.go file (#59929) + } else if len(pkg.CompiledGoFiles) == 0 { + // Work around for pre-go.1.11 versions of go list. + // TODO(matloob): they should be handled by the fallback. + // Can we delete this? + pkg.CompiledGoFiles = pkg.GoFiles } // Assume go list emits only absolute paths for Dir. @@ -663,16 +592,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse response.Roots = append(response.Roots, pkg.ID) } - // Work around for pre-go.1.11 versions of go list. - // TODO(matloob): they should be handled by the fallback. - // Can we delete this? - if len(pkg.CompiledGoFiles) == 0 { - pkg.CompiledGoFiles = pkg.GoFiles - } - // Temporary work-around for golang/go#39986. Parse filenames out of // error messages. This happens if there are unrecoverable syntax // errors in the source, so we can't match on a specific error message. + // + // TODO(rfindley): remove this heuristic, in favor of considering + // InvalidGoFiles from the list driver. if err := p.Error; err != nil && state.shouldAddFilenameFromError(p) { addFilenameFromPos := func(pos string) bool { split := strings.Split(pos, ":") @@ -891,6 +816,15 @@ func golistargs(cfg *Config, words []string, goVersion int) []string { // probably because you'd just get the TestMain. fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0 && !usesExportData(cfg)), } + + // golang/go#60456: with go1.21 and later, go list serves pgo variants, which + // can be costly to compute and may result in redundant processing for the + // caller. Disable these variants. If someone wants to add e.g. a NeedPGO + // mode flag, that should be a separate proposal. + if goVersion >= 21 { + fullargs = append(fullargs, "-pgo=off") + } + fullargs = append(fullargs, cfg.BuildFlags...) fullargs = append(fullargs, "--") fullargs = append(fullargs, words...) @@ -1100,7 +1034,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err if len(state.cfg.Overlay) == 0 { return "", func() {}, nil } - dir, err := ioutil.TempDir("", "gopackages-*") + dir, err := os.MkdirTemp("", "gopackages-*") if err != nil { return "", nil, err } @@ -1119,7 +1053,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err // Create a unique filename for the overlaid files, to avoid // creating nested directories. noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "") - f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator)) + f, err := os.CreateTemp(dir, fmt.Sprintf("*-%s", noSeparator)) if err != nil { return "", func() {}, err } @@ -1137,7 +1071,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err } // Write out the overlay file that contains the filepath mappings. filename = filepath.Join(dir, "overlay.json") - if err := ioutil.WriteFile(filename, b, 0665); err != nil { + if err := os.WriteFile(filename, b, 0665); err != nil { return "", func() {}, err } return filename, cleanup, nil diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go index 9576b472f..d823c474a 100644 --- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go +++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -6,314 +6,11 @@ package packages import ( "encoding/json" - "fmt" - "go/parser" - "go/token" - "os" "path/filepath" - "regexp" - "sort" - "strconv" - "strings" "golang.org/x/tools/internal/gocommand" ) -// processGolistOverlay provides rudimentary support for adding -// files that don't exist on disk to an overlay. The results can be -// sometimes incorrect. -// TODO(matloob): Handle unsupported cases, including the following: -// - determining the correct package to add given a new import path -func (state *golistState) processGolistOverlay(response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) { - havePkgs := make(map[string]string) // importPath -> non-test package ID - needPkgsSet := make(map[string]bool) - modifiedPkgsSet := make(map[string]bool) - - pkgOfDir := make(map[string][]*Package) - for _, pkg := range response.dr.Packages { - // This is an approximation of import path to id. This can be - // wrong for tests, vendored packages, and a number of other cases. - havePkgs[pkg.PkgPath] = pkg.ID - dir, err := commonDir(pkg.GoFiles) - if err != nil { - return nil, nil, err - } - if dir != "" { - pkgOfDir[dir] = append(pkgOfDir[dir], pkg) - } - } - - // If no new imports are added, it is safe to avoid loading any needPkgs. - // Otherwise, it's hard to tell which package is actually being loaded - // (due to vendoring) and whether any modified package will show up - // in the transitive set of dependencies (because new imports are added, - // potentially modifying the transitive set of dependencies). - var overlayAddsImports bool - - // If both a package and its test package are created by the overlay, we - // need the real package first. Process all non-test files before test - // files, and make the whole process deterministic while we're at it. - var overlayFiles []string - for opath := range state.cfg.Overlay { - overlayFiles = append(overlayFiles, opath) - } - sort.Slice(overlayFiles, func(i, j int) bool { - iTest := strings.HasSuffix(overlayFiles[i], "_test.go") - jTest := strings.HasSuffix(overlayFiles[j], "_test.go") - if iTest != jTest { - return !iTest // non-tests are before tests. - } - return overlayFiles[i] < overlayFiles[j] - }) - for _, opath := range overlayFiles { - contents := state.cfg.Overlay[opath] - base := filepath.Base(opath) - dir := filepath.Dir(opath) - var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant - var testVariantOf *Package // if opath is a test file, this is the package it is testing - var fileExists bool - isTestFile := strings.HasSuffix(opath, "_test.go") - pkgName, ok := extractPackageName(opath, contents) - if !ok { - // Don't bother adding a file that doesn't even have a parsable package statement - // to the overlay. - continue - } - // If all the overlay files belong to a different package, change the - // package name to that package. - maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir]) - nextPackage: - for _, p := range response.dr.Packages { - if pkgName != p.Name && p.ID != "command-line-arguments" { - continue - } - for _, f := range p.GoFiles { - if !sameFile(filepath.Dir(f), dir) { - continue - } - // Make sure to capture information on the package's test variant, if needed. - if isTestFile && !hasTestFiles(p) { - // TODO(matloob): Are there packages other than the 'production' variant - // of a package that this can match? This shouldn't match the test main package - // because the file is generated in another directory. - testVariantOf = p - continue nextPackage - } else if !isTestFile && hasTestFiles(p) { - // We're examining a test variant, but the overlaid file is - // a non-test file. Because the overlay implementation - // (currently) only adds a file to one package, skip this - // package, so that we can add the file to the production - // variant of the package. (https://golang.org/issue/36857 - // tracks handling overlays on both the production and test - // variant of a package). - continue nextPackage - } - if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath { - // We have already seen the production version of the - // for which p is a test variant. - if hasTestFiles(p) { - testVariantOf = pkg - } - } - pkg = p - if filepath.Base(f) == base { - fileExists = true - } - } - } - // The overlay could have included an entirely new package or an - // ad-hoc package. An ad-hoc package is one that we have manually - // constructed from inadequate `go list` results for a file= query. - // It will have the ID command-line-arguments. - if pkg == nil || pkg.ID == "command-line-arguments" { - // Try to find the module or gopath dir the file is contained in. - // Then for modules, add the module opath to the beginning. - pkgPath, ok, err := state.getPkgPath(dir) - if err != nil { - return nil, nil, err - } - if !ok { - break - } - var forTest string // only set for x tests - isXTest := strings.HasSuffix(pkgName, "_test") - if isXTest { - forTest = pkgPath - pkgPath += "_test" - } - id := pkgPath - if isTestFile { - if isXTest { - id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest) - } else { - id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) - } - } - if pkg != nil { - // TODO(rstambler): We should change the package's path and ID - // here. The only issue is that this messes with the roots. - } else { - // Try to reclaim a package with the same ID, if it exists in the response. - for _, p := range response.dr.Packages { - if reclaimPackage(p, id, opath, contents) { - pkg = p - break - } - } - // Otherwise, create a new package. - if pkg == nil { - pkg = &Package{ - PkgPath: pkgPath, - ID: id, - Name: pkgName, - Imports: make(map[string]*Package), - } - response.addPackage(pkg) - havePkgs[pkg.PkgPath] = id - // Add the production package's sources for a test variant. - if isTestFile && !isXTest && testVariantOf != nil { - pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) - pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) - // Add the package under test and its imports to the test variant. - pkg.forTest = testVariantOf.PkgPath - for k, v := range testVariantOf.Imports { - pkg.Imports[k] = &Package{ID: v.ID} - } - } - if isXTest { - pkg.forTest = forTest - } - } - } - } - if !fileExists { - pkg.GoFiles = append(pkg.GoFiles, opath) - // TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior - // if the file will be ignored due to its build tags. - pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath) - modifiedPkgsSet[pkg.ID] = true - } - imports, err := extractImports(opath, contents) - if err != nil { - // Let the parser or type checker report errors later. - continue - } - for _, imp := range imports { - // TODO(rstambler): If the package is an x test and the import has - // a test variant, make sure to replace it. - if _, found := pkg.Imports[imp]; found { - continue - } - overlayAddsImports = true - id, ok := havePkgs[imp] - if !ok { - var err error - id, err = state.resolveImport(dir, imp) - if err != nil { - return nil, nil, err - } - } - pkg.Imports[imp] = &Package{ID: id} - // Add dependencies to the non-test variant version of this package as well. - if testVariantOf != nil { - testVariantOf.Imports[imp] = &Package{ID: id} - } - } - } - - // toPkgPath guesses the package path given the id. - toPkgPath := func(sourceDir, id string) (string, error) { - if i := strings.IndexByte(id, ' '); i >= 0 { - return state.resolveImport(sourceDir, id[:i]) - } - return state.resolveImport(sourceDir, id) - } - - // Now that new packages have been created, do another pass to determine - // the new set of missing packages. - for _, pkg := range response.dr.Packages { - for _, imp := range pkg.Imports { - if len(pkg.GoFiles) == 0 { - return nil, nil, fmt.Errorf("cannot resolve imports for package %q with no Go files", pkg.PkgPath) - } - pkgPath, err := toPkgPath(filepath.Dir(pkg.GoFiles[0]), imp.ID) - if err != nil { - return nil, nil, err - } - if _, ok := havePkgs[pkgPath]; !ok { - needPkgsSet[pkgPath] = true - } - } - } - - if overlayAddsImports { - needPkgs = make([]string, 0, len(needPkgsSet)) - for pkg := range needPkgsSet { - needPkgs = append(needPkgs, pkg) - } - } - modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) - for pkg := range modifiedPkgsSet { - modifiedPkgs = append(modifiedPkgs, pkg) - } - return modifiedPkgs, needPkgs, err -} - -// resolveImport finds the ID of a package given its import path. -// In particular, it will find the right vendored copy when in GOPATH mode. -func (state *golistState) resolveImport(sourceDir, importPath string) (string, error) { - env, err := state.getEnv() - if err != nil { - return "", err - } - if env["GOMOD"] != "" { - return importPath, nil - } - - searchDir := sourceDir - for { - vendorDir := filepath.Join(searchDir, "vendor") - exists, ok := state.vendorDirs[vendorDir] - if !ok { - info, err := os.Stat(vendorDir) - exists = err == nil && info.IsDir() - state.vendorDirs[vendorDir] = exists - } - - if exists { - vendoredPath := filepath.Join(vendorDir, importPath) - if info, err := os.Stat(vendoredPath); err == nil && info.IsDir() { - // We should probably check for .go files here, but shame on anyone who fools us. - path, ok, err := state.getPkgPath(vendoredPath) - if err != nil { - return "", err - } - if ok { - return path, nil - } - } - } - - // We know we've hit the top of the filesystem when we Dir / and get /, - // or C:\ and get C:\, etc. - next := filepath.Dir(searchDir) - if next == searchDir { - break - } - searchDir = next - } - return importPath, nil -} - -func hasTestFiles(p *Package) bool { - for _, f := range p.GoFiles { - if strings.HasSuffix(f, "_test.go") { - return true - } - } - return false -} - // determineRootDirs returns a mapping from absolute directories that could // contain code to their corresponding import path prefixes. func (state *golistState) determineRootDirs() (map[string]string, error) { @@ -384,192 +81,3 @@ func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) { } return m, nil } - -func extractImports(filename string, contents []byte) ([]string, error) { - f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset? - if err != nil { - return nil, err - } - var res []string - for _, imp := range f.Imports { - quotedPath := imp.Path.Value - path, err := strconv.Unquote(quotedPath) - if err != nil { - return nil, err - } - res = append(res, path) - } - return res, nil -} - -// reclaimPackage attempts to reuse a package that failed to load in an overlay. -// -// If the package has errors and has no Name, GoFiles, or Imports, -// then it's possible that it doesn't yet exist on disk. -func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool { - // TODO(rstambler): Check the message of the actual error? - // It differs between $GOPATH and module mode. - if pkg.ID != id { - return false - } - if len(pkg.Errors) != 1 { - return false - } - if pkg.Name != "" || pkg.ExportFile != "" { - return false - } - if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 { - return false - } - if len(pkg.Imports) > 0 { - return false - } - pkgName, ok := extractPackageName(filename, contents) - if !ok { - return false - } - pkg.Name = pkgName - pkg.Errors = nil - return true -} - -func extractPackageName(filename string, contents []byte) (string, bool) { - // TODO(rstambler): Check the message of the actual error? - // It differs between $GOPATH and module mode. - f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset? - if err != nil { - return "", false - } - return f.Name.Name, true -} - -// commonDir returns the directory that all files are in, "" if files is empty, -// or an error if they aren't in the same directory. -func commonDir(files []string) (string, error) { - seen := make(map[string]bool) - for _, f := range files { - seen[filepath.Dir(f)] = true - } - if len(seen) > 1 { - return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen) - } - for k := range seen { - // seen has only one element; return it. - return k, nil - } - return "", nil // no files -} - -// It is possible that the files in the disk directory dir have a different package -// name from newName, which is deduced from the overlays. If they all have a different -// package name, and they all have the same package name, then that name becomes -// the package name. -// It returns true if it changes the package name, false otherwise. -func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) { - names := make(map[string]int) - for _, p := range pkgsOfDir { - names[p.Name]++ - } - if len(names) != 1 { - // some files are in different packages - return - } - var oldName string - for k := range names { - oldName = k - } - if newName == oldName { - return - } - // We might have a case where all of the package names in the directory are - // the same, but the overlay file is for an x test, which belongs to its - // own package. If the x test does not yet exist on disk, we may not yet - // have its package name on disk, but we should not rename the packages. - // - // We use a heuristic to determine if this file belongs to an x test: - // The test file should have a package name whose package name has a _test - // suffix or looks like "newName_test". - maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test") - if isTestFile && maybeXTest { - return - } - for _, p := range pkgsOfDir { - p.Name = newName - } -} - -// This function is copy-pasted from -// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360. -// It should be deleted when we remove support for overlays from go/packages. -// -// NOTE: This does not handle any ./... or ./ style queries, as this function -// doesn't know the working directory. -// -// matchPattern(pattern)(name) reports whether -// name matches pattern. Pattern is a limited glob -// pattern in which '...' means 'any string' and there -// is no other special syntax. -// Unfortunately, there are two special cases. Quoting "go help packages": -// -// First, /... at the end of the pattern can match an empty string, -// so that net/... matches both net and packages in its subdirectories, like net/http. -// Second, any slash-separated pattern element containing a wildcard never -// participates in a match of the "vendor" element in the path of a vendored -// package, so that ./... does not match packages in subdirectories of -// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. -// Note, however, that a directory named vendor that itself contains code -// is not a vendored package: cmd/vendor would be a command named vendor, -// and the pattern cmd/... matches it. -func matchPattern(pattern string) func(name string) bool { - // Convert pattern to regular expression. - // The strategy for the trailing /... is to nest it in an explicit ? expression. - // The strategy for the vendor exclusion is to change the unmatchable - // vendor strings to a disallowed code point (vendorChar) and to use - // "(anything but that codepoint)*" as the implementation of the ... wildcard. - // This is a bit complicated but the obvious alternative, - // namely a hand-written search like in most shell glob matchers, - // is too easy to make accidentally exponential. - // Using package regexp guarantees linear-time matching. - - const vendorChar = "\x00" - - if strings.Contains(pattern, vendorChar) { - return func(name string) bool { return false } - } - - re := regexp.QuoteMeta(pattern) - re = replaceVendor(re, vendorChar) - switch { - case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`): - re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)` - case re == vendorChar+`/\.\.\.`: - re = `(/vendor|/` + vendorChar + `/\.\.\.)` - case strings.HasSuffix(re, `/\.\.\.`): - re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?` - } - re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`) - - reg := regexp.MustCompile(`^` + re + `$`) - - return func(name string) bool { - if strings.Contains(name, vendorChar) { - return false - } - return reg.MatchString(replaceVendor(name, vendorChar)) - } -} - -// replaceVendor returns the result of replacing -// non-trailing vendor path elements in x with repl. -func replaceVendor(x, repl string) string { - if !strings.Contains(x, "vendor") { - return x - } - elem := strings.Split(x, "/") - for i := 0; i < len(elem)-1; i++ { - if elem[i] == "vendor" { - elem[i] = repl - } - } - return strings.Join(elem, "/") -} diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go index 0f1505b80..81e9e6a72 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -16,7 +16,6 @@ import ( "go/token" "go/types" "io" - "io/ioutil" "log" "os" "path/filepath" @@ -28,8 +27,8 @@ import ( "golang.org/x/tools/go/gcexportdata" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" - "golang.org/x/tools/internal/typeparams" "golang.org/x/tools/internal/typesinternal" + "golang.org/x/tools/internal/versions" ) // A LoadMode controls the amount of detail to return when loading. @@ -220,8 +219,10 @@ type driverResponse struct { // lists of multiple drivers, go/packages will fall back to the next driver. NotHandled bool - // Sizes, if not nil, is the types.Sizes to use when type checking. - Sizes *types.StdSizes + // Compiler and Arch are the arguments pass of types.SizesFor + // to get a types.Sizes to use when type checking. + Compiler string + Arch string // Roots is the set of package IDs that make up the root packages. // We have to encode this separately because when we encode a single package @@ -257,31 +258,52 @@ type driverResponse struct { // proceeding with further analysis. The PrintErrors function is // provided for convenient display of all errors. func Load(cfg *Config, patterns ...string) ([]*Package, error) { - l := newLoader(cfg) - response, err := defaultDriver(&l.Config, patterns...) + ld := newLoader(cfg) + response, external, err := defaultDriver(&ld.Config, patterns...) if err != nil { return nil, err } - l.sizes = response.Sizes - return l.refine(response) + + ld.sizes = types.SizesFor(response.Compiler, response.Arch) + if ld.sizes == nil && ld.Config.Mode&(NeedTypes|NeedTypesSizes|NeedTypesInfo) != 0 { + // Type size information is needed but unavailable. + if external { + // An external driver may fail to populate the Compiler/GOARCH fields, + // especially since they are relatively new (see #63700). + // Provide a sensible fallback in this case. + ld.sizes = types.SizesFor("gc", runtime.GOARCH) + if ld.sizes == nil { // gccgo-only arch + ld.sizes = types.SizesFor("gc", "amd64") + } + } else { + // Go list should never fail to deliver accurate size information. + // Reject the whole Load since the error is the same for every package. + return nil, fmt.Errorf("can't determine type sizes for compiler %q on GOARCH %q", + response.Compiler, response.Arch) + } + } + + return ld.refine(response) } // defaultDriver is a driver that implements go/packages' fallback behavior. // It will try to request to an external driver, if one exists. If there's // no external driver, or the driver returns a response with NotHandled set, // defaultDriver will fall back to the go list driver. -func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) { - driver := findExternalDriver(cfg) - if driver == nil { - driver = goListDriver - } - response, err := driver(cfg, patterns...) - if err != nil { - return response, err - } else if response.NotHandled { - return goListDriver(cfg, patterns...) +// The boolean result indicates that an external driver handled the request. +func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, bool, error) { + if driver := findExternalDriver(cfg); driver != nil { + response, err := driver(cfg, patterns...) + if err != nil { + return nil, false, err + } else if !response.NotHandled { + return response, true, nil + } + // (fall through) } - return response, nil + + response, err := goListDriver(cfg, patterns...) + return response, false, err } // A Package describes a loaded Go package. @@ -308,6 +330,9 @@ type Package struct { TypeErrors []types.Error // GoFiles lists the absolute file paths of the package's Go source files. + // It may include files that should not be compiled, for example because + // they contain non-matching build tags, are documentary pseudo-files such as + // unsafe/unsafe.go or builtin/builtin.go, or are subject to cgo preprocessing. GoFiles []string // CompiledGoFiles lists the absolute file paths of the package's source @@ -407,12 +432,6 @@ func init() { packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError { return p.(*Package).depsErrors } - packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner { - return config.(*Config).gocmdRunner - } - packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) { - config.(*Config).gocmdRunner = runner - } packagesinternal.SetModFile = func(config interface{}, value string) { config.(*Config).modFile = value } @@ -549,7 +568,7 @@ type loaderPackage struct { type loader struct { pkgs map[string]*loaderPackage Config - sizes types.Sizes + sizes types.Sizes // non-nil if needed by mode parseCache map[string]*parseValue parseCacheMu sync.Mutex exportMu sync.Mutex // enforces mutual exclusion of exportdata operations @@ -627,7 +646,7 @@ func newLoader(cfg *Config) *loader { return ld } -// refine connects the supplied packages into a graph and then adds type and +// refine connects the supplied packages into a graph and then adds type // and syntax information as requested by the LoadMode. func (ld *loader) refine(response *driverResponse) ([]*Package, error) { roots := response.Roots @@ -674,39 +693,38 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) { } } - // Materialize the import graph. - - const ( - white = 0 // new - grey = 1 // in progress - black = 2 // complete - ) - - // visit traverses the import graph, depth-first, - // and materializes the graph as Packages.Imports. - // - // Valid imports are saved in the Packages.Import map. - // Invalid imports (cycles and missing nodes) are saved in the importErrors map. - // Thus, even in the presence of both kinds of errors, the Import graph remains a DAG. - // - // visit returns whether the package needs src or has a transitive - // dependency on a package that does. These are the only packages - // for which we load source code. - var stack []*loaderPackage - var visit func(lpkg *loaderPackage) bool - var srcPkgs []*loaderPackage - visit = func(lpkg *loaderPackage) bool { - switch lpkg.color { - case black: - return lpkg.needsrc - case grey: - panic("internal error: grey node") - } - lpkg.color = grey - stack = append(stack, lpkg) // push - stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports - // If NeedImports isn't set, the imports fields will all be zeroed out. - if ld.Mode&NeedImports != 0 { + if ld.Mode&NeedImports != 0 { + // Materialize the import graph. + + const ( + white = 0 // new + grey = 1 // in progress + black = 2 // complete + ) + + // visit traverses the import graph, depth-first, + // and materializes the graph as Packages.Imports. + // + // Valid imports are saved in the Packages.Import map. + // Invalid imports (cycles and missing nodes) are saved in the importErrors map. + // Thus, even in the presence of both kinds of errors, + // the Import graph remains a DAG. + // + // visit returns whether the package needs src or has a transitive + // dependency on a package that does. These are the only packages + // for which we load source code. + var stack []*loaderPackage + var visit func(lpkg *loaderPackage) bool + visit = func(lpkg *loaderPackage) bool { + switch lpkg.color { + case black: + return lpkg.needsrc + case grey: + panic("internal error: grey node") + } + lpkg.color = grey + stack = append(stack, lpkg) // push + stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports lpkg.Imports = make(map[string]*Package, len(stubs)) for importPath, ipkg := range stubs { var importErr error @@ -730,40 +748,39 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) { } lpkg.Imports[importPath] = imp.Package } - } - if lpkg.needsrc { - srcPkgs = append(srcPkgs, lpkg) - } - if ld.Mode&NeedTypesSizes != 0 { - lpkg.TypesSizes = ld.sizes - } - stack = stack[:len(stack)-1] // pop - lpkg.color = black - return lpkg.needsrc - } + // Complete type information is required for the + // immediate dependencies of each source package. + if lpkg.needsrc && ld.Mode&NeedTypes != 0 { + for _, ipkg := range lpkg.Imports { + ld.pkgs[ipkg.ID].needtypes = true + } + } - if ld.Mode&NeedImports == 0 { - // We do this to drop the stub import packages that we are not even going to try to resolve. - for _, lpkg := range initial { - lpkg.Imports = nil + // NeedTypeSizes causes TypeSizes to be set even + // on packages for which types aren't needed. + if ld.Mode&NeedTypesSizes != 0 { + lpkg.TypesSizes = ld.sizes + } + stack = stack[:len(stack)-1] // pop + lpkg.color = black + + return lpkg.needsrc } - } else { + // For each initial package, create its import DAG. for _, lpkg := range initial { visit(lpkg) } - } - if ld.Mode&NeedImports != 0 && ld.Mode&NeedTypes != 0 { - for _, lpkg := range srcPkgs { - // Complete type information is required for the - // immediate dependencies of each source package. - for _, ipkg := range lpkg.Imports { - imp := ld.pkgs[ipkg.ID] - imp.needtypes = true - } + + } else { + // !NeedImports: drop the stub (ID-only) import packages + // that we are not even going to try to resolve. + for _, lpkg := range initial { + lpkg.Imports = nil } } + // Load type data and syntax if needed, starting at // the initial packages (roots of the import DAG). if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { @@ -997,10 +1014,11 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), } - typeparams.InitInstanceInfo(lpkg.TypesInfo) + versions.InitFileVersions(lpkg.TypesInfo) lpkg.TypesSizes = ld.sizes importer := importerFunc(func(path string) (*types.Package, error) { @@ -1038,7 +1056,10 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial, Error: appendError, - Sizes: ld.sizes, + Sizes: ld.sizes, // may be nil + } + if lpkg.Module != nil && lpkg.Module.GoVersion != "" { + typesinternal.SetGoVersion(tc, "go"+lpkg.Module.GoVersion) } if (ld.Mode & typecheckCgo) != 0 { if !typesinternal.SetUsesCgo(tc) { @@ -1119,7 +1140,7 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) { var err error if src == nil { ioLimit <- true // wait - src, err = ioutil.ReadFile(filename) + src, err = os.ReadFile(filename) <-ioLimit // signal } if err != nil { diff --git a/vendor/golang.org/x/tools/go/ssa/builder.go b/vendor/golang.org/x/tools/go/ssa/builder.go index be8d36a6e..8622dfc53 100644 --- a/vendor/golang.org/x/tools/go/ssa/builder.go +++ b/vendor/golang.org/x/tools/go/ssa/builder.go @@ -4,106 +4,73 @@ package ssa -// This file implements the BUILD phase of SSA construction. +// This file defines the builder, which builds SSA-form IR for function bodies. // -// SSA construction has two phases, CREATE and BUILD. In the CREATE phase -// (create.go), all packages are constructed and type-checked and -// definitions of all package members are created, method-sets are -// computed, and wrapper methods are synthesized. -// ssa.Packages are created in arbitrary order. +// SSA construction has two phases, "create" and "build". First, one +// or more packages are created in any order by a sequence of calls to +// CreatePackage, either from syntax or from mere type information. +// Each created package has a complete set of Members (const, var, +// type, func) that can be accessed through methods like +// Program.FuncValue. // -// In the BUILD phase (builder.go), the builder traverses the AST of -// each Go source function and generates SSA instructions for the -// function body. Initializer expressions for package-level variables -// are emitted to the package's init() function in the order specified -// by go/types.Info.InitOrder, then code for each function in the -// package is generated in lexical order. -// The BUILD phases for distinct packages are independent and are -// executed in parallel. +// It is not necessary to call CreatePackage for all dependencies of +// each syntax package, only for its direct imports. (In future +// perhaps even this restriction may be lifted.) // -// TODO(adonovan): indeed, building functions is now embarrassingly parallel. -// Audit for concurrency then benchmark using more goroutines. +// Second, packages created from syntax are built, by one or more +// calls to Package.Build, which may be concurrent; or by a call to +// Program.Build, which builds all packages in parallel. Building +// traverses the type-annotated syntax tree of each function body and +// creates SSA-form IR, a control-flow graph of instructions, +// populating fields such as Function.Body, .Params, and others. // -// State: +// Building may create additional methods, including: +// - wrapper methods (e.g. for embeddding, or implicit &recv) +// - bound method closures (e.g. for use(recv.f)) +// - thunks (e.g. for use(I.f) or use(T.f)) +// - generic instances (e.g. to produce f[int] from f[any]). +// As these methods are created, they are added to the build queue, +// and then processed in turn, until a fixed point is reached, +// Since these methods might belong to packages that were not +// created (by a call to CreatePackage), their Pkg field is unset. // -// The Package's and Program's indices (maps) are populated and -// mutated during the CREATE phase, but during the BUILD phase they -// remain constant. The sole exception is Prog.methodSets and its -// related maps, which are protected by a dedicated mutex. +// Instances of generic functions may be either instantiated (f[int] +// is a copy of f[T] with substitutions) or wrapped (f[int] delegates +// to f[T]), depending on the availability of generic syntax and the +// InstantiateGenerics mode flag. // -// Generic functions declared in a package P can be instantiated from functions -// outside of P. This happens independently of the CREATE and BUILD phase of P. +// Each package has an initializer function named "init" that calls +// the initializer functions of each direct import, computes and +// assigns the initial value of each global variable, and calls each +// source-level function named "init". (These generate SSA functions +// named "init#1", "init#2", etc.) // -// Locks: +// Runtime types // -// Mutexes are currently acquired according to the following order: -// Prog.methodsMu ⊃ canonizer.mu ⊃ printMu -// where x ⊃ y denotes that y can be acquired while x is held -// and x cannot be acquired while y is held. +// Each MakeInterface operation is a conversion from a non-interface +// type to an interface type. The semantics of this operation requires +// a runtime type descriptor, which is the type portion of an +// interface, and the value abstracted by reflect.Type. // -// Synthetics: +// The program accumulates all non-parameterized types that are +// encountered as MakeInterface operands, along with all types that +// may be derived from them using reflection. This set is available as +// Program.RuntimeTypes, and the methods of these types may be +// reachable via interface calls or reflection even if they are never +// referenced from the SSA IR. (In practice, algorithms such as RTA +// that compute reachability from package main perform their own +// tracking of runtime types at a finer grain, so this feature is not +// very useful.) // -// During the BUILD phase new functions can be created and built. These include: -// - wrappers (wrappers, bounds, thunks) -// - generic function instantiations -// These functions do not belong to a specific Pkg (Pkg==nil). Instead the -// Package that led to them being CREATED is obligated to ensure these -// are BUILT during the BUILD phase of the Package. +// Function literals // -// Runtime types: +// Anonymous functions must be built as soon as they are encountered, +// as it may affect locals of the enclosing function, but they are not +// marked 'built' until the end of the outermost enclosing function. +// (Among other things, this causes them to be logged in top-down order.) // -// A concrete type is a type that is fully monomorphized with concrete types, -// i.e. it cannot reach a TypeParam type. -// Some concrete types require full runtime type information. Cases -// include checking whether a type implements an interface or -// interpretation by the reflect package. All such types that may require -// this information will have all of their method sets built and will be added to Prog.methodSets. -// A type T is considered to require runtime type information if it is -// a runtime type and has a non-empty method set and either: -// - T flows into a MakeInterface instructions, -// - T appears in a concrete exported member, or -// - T is a type reachable from a type S that has non-empty method set. -// For any such type T, method sets must be created before the BUILD -// phase of the package is done. -// -// Function literals: -// -// The BUILD phase of a function literal (anonymous function) is tied to the -// BUILD phase of the enclosing parent function. The FreeVars of an anonymous -// function are discovered by building the anonymous function. This in turn -// changes which variables must be bound in a MakeClosure instruction in the -// parent. Anonymous functions also track where they are referred to in their -// parent function. -// -// Happens-before: -// -// The above discussion leads to the following happens-before relation for -// the BUILD and CREATE phases. -// The happens-before relation (with X 0 { targs := fn.subst.types(instanceArgs(fn.info, e)) - callee = fn.Prog.needsInstance(callee, targs, b.created) + callee = callee.instance(targs, b.created) } return callee } // Local var. - return emitLoad(fn, fn.lookup(obj, false)) // var (address) + return emitLoad(fn, fn.lookup(obj.(*types.Var), false)) // var (address) case *ast.SelectorExpr: sel := fn.selection(e) @@ -823,7 +787,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { case types.MethodExpr: // (*T).f or T.f, the method f from the method-set of type T. // The result is a "thunk". - thunk := makeThunk(fn.Prog, sel, b.created) + thunk := createThunk(fn.Prog, sel, b.created) return emitConv(fn, thunk, fn.typ(tv.Type)) case types.MethodVal: @@ -831,14 +795,14 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { // The result is a "bound". obj := sel.obj.(*types.Func) rt := fn.typ(recvType(obj)) - wantAddr := isPointer(rt) + _, wantAddr := deref(rt) escaping := true v := b.receiver(fn, e.X, wantAddr, escaping, sel) if types.IsInterface(rt) { // If v may be an interface type I (after instantiating), // we must emit a check that v is non-nil. - if recv, ok := sel.recv.(*typeparams.TypeParam); ok { + if recv, ok := sel.recv.(*types.TypeParam); ok { // Emit a nil check if any possible instantiation of the // type parameter is an interface type. if typeSetOf(recv).Len() > 0 { @@ -858,7 +822,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { } else { // non-type param interface // Emit nil check: typeassert v.(I). - emitTypeAssert(fn, v, rt, token.NoPos) + emitTypeAssert(fn, v, rt, e.Sel.Pos()) } } if targs := receiverTypeArgs(obj); len(targs) > 0 { @@ -866,7 +830,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { obj = fn.Prog.canon.instantiateMethod(obj, fn.subst.types(targs), fn.Prog.ctxt) } c := &MakeClosure{ - Fn: makeBound(fn.Prog, obj, b.created), + Fn: createBound(fn.Prog, obj, b.created), Bindings: []Value{v}, } c.setPos(e.Sel.Pos()) @@ -884,7 +848,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value { panic("unexpected expression-relative selector") - case *typeparams.IndexListExpr: + case *ast.IndexListExpr: // f[X, Y] must be a generic function if !instance(fn.info, e.X) { panic("unexpected expression-could not match index list to instantiation") @@ -952,14 +916,14 @@ func (b *builder) stmtList(fn *Function, list []ast.Stmt) { // returns the effective receiver after applying the implicit field // selections of sel. // -// wantAddr requests that the result is an an address. If +// wantAddr requests that the result is an address. If // !sel.indirect, this may require that e be built in addr() mode; it // must thus be addressable. // // escaping is defined as per builder.addr(). func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, sel *selection) Value { var v Value - if wantAddr && !sel.indirect && !isPointer(fn.typeOf(e)) { + if _, eptr := deref(fn.typeOf(e)); wantAddr && !sel.indirect && !eptr { v = b.addr(fn, e, escaping).address(fn) } else { v = b.expr(fn, e) @@ -968,7 +932,10 @@ func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, se last := len(sel.index) - 1 // The position of implicit selection is the position of the inducing receiver expression. v = emitImplicitSelections(fn, v, sel.index[:last], e.Pos()) - if !wantAddr && isPointer(v.Type()) { + if types.IsInterface(v.Type()) { + // When v is an interface, sel.Kind()==MethodValue and v.f is invoked. + // So v is not loaded, even if v has a pointer core type. + } else if _, vptr := deref(v.Type()); !wantAddr && vptr { v = emitLoad(fn, v) } return v @@ -987,7 +954,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { obj := sel.obj.(*types.Func) recv := recvType(obj) - wantAddr := isPointer(recv) + _, wantAddr := deref(recv) escaping := true v := b.receiver(fn, selector.X, wantAddr, escaping, sel) if types.IsInterface(recv) { @@ -996,11 +963,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) { c.Method = obj } else { // "Call"-mode call. - callee := fn.Prog.originFunc(obj) - if callee.typeparams.Len() > 0 { - callee = fn.Prog.needsInstance(callee, receiverTypeArgs(obj), b.created) - } - c.Value = callee + c.Value = fn.Prog.objectMethod(obj, b.created) c.Args = append(c.Args, v) } return @@ -1092,9 +1055,8 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx } else { // Replace a suffix of args with a slice containing it. at := types.NewArray(vt, int64(len(varargs))) - a := emitNew(fn, at, token.NoPos) + a := emitNew(fn, at, token.NoPos, "varargs") a.setPos(e.Rparen) - a.Comment = "varargs" for i, arg := range varargs { iaddr := &IndexAddr{ X: a, @@ -1141,7 +1103,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) { // 1:1 assignment for i, id := range spec.Names { if !isBlankIdent(id) { - fn.addLocalForIdent(id) + emitLocalVar(fn, identVar(fn, id)) } lval := b.addr(fn, id, false) // non-escaping b.assign(fn, lval, spec.Values[i], true, nil) @@ -1152,7 +1114,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) { // Locals are implicitly zero-initialized. for _, id := range spec.Names { if !isBlankIdent(id) { - lhs := fn.addLocalForIdent(id) + lhs := emitLocalVar(fn, identVar(fn, id)) if fn.debugInfo() { emitDebugRef(fn, id, lhs, true) } @@ -1164,7 +1126,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) { tuple := b.exprN(fn, spec.Values[0]) for i, id := range spec.Names { if !isBlankIdent(id) { - fn.addLocalForIdent(id) + emitLocalVar(fn, identVar(fn, id)) lhs := b.addr(fn, id, false) // non-escaping lhs.store(fn, emitExtract(fn, tuple, i)) } @@ -1184,8 +1146,8 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) { var lval lvalue = blank{} if !isBlankIdent(lhs) { if isDef { - if obj := fn.info.Defs[lhs.(*ast.Ident)]; obj != nil { - fn.addNamedLocal(obj) + if obj, ok := fn.info.Defs[lhs.(*ast.Ident)].(*types.Var); ok { + emitLocalVar(fn, obj) isZero[i] = true } } @@ -1253,37 +1215,13 @@ func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 { // literal has type *T behaves like &T{}. // In that case, addr must hold a T, not a *T. func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero bool, sb *storebuf) { - typ := deref(fn.typeOf(e)) // type with name [may be type param] - t := deref(typeparams.CoreType(typ)).Underlying() // core type for comp lit case - // Computing typ and t is subtle as these handle pointer types. - // For example, &T{...} is valid even for maps and slices. - // Also typ should refer to T (not *T) while t should be the core type of T. - // - // To show the ordering to take into account, consider the composite literal - // expressions `&T{f: 1}` and `{f: 1}` within the expression `[]S{{f: 1}}` here: - // type N struct{f int} - // func _[T N, S *N]() { - // _ = &T{f: 1} - // _ = []S{{f: 1}} - // } - // For `&T{f: 1}`, we compute `typ` and `t` as: - // typeOf(&T{f: 1}) == *T - // deref(*T) == T (typ) - // CoreType(T) == N - // deref(N) == N - // N.Underlying() == struct{f int} (t) - // For `{f: 1}` in `[]S{{f: 1}}`, we compute `typ` and `t` as: - // typeOf({f: 1}) == S - // deref(S) == S (typ) - // CoreType(S) == *N - // deref(*N) == N - // N.Underlying() == struct{f int} (t) - switch t := t.(type) { + typ, _ := deref(fn.typeOf(e)) // type with name [may be type param] + switch t := typeparams.CoreType(typ).(type) { case *types.Struct: if !isZero && len(e.Elts) != t.NumFields() { // memclear - sb.store(&address{addr, e.Lbrace, nil}, - zeroValue(fn, deref(addr.Type()))) + zt, _ := deref(addr.Type()) + sb.store(&address{addr, e.Lbrace, nil}, zeroConst(zt)) isZero = true } for i, e := range e.Elts { @@ -1318,17 +1256,15 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero switch t := t.(type) { case *types.Slice: at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts)) - alloc := emitNew(fn, at, e.Lbrace) - alloc.Comment = "slicelit" - array = alloc + array = emitNew(fn, at, e.Lbrace, "slicelit") case *types.Array: at = t array = addr if !isZero && int64(len(e.Elts)) != at.Len() { // memclear - sb.store(&address{array, e.Lbrace, nil}, - zeroValue(fn, deref(array.Type()))) + zt, _ := deref(array.Type()) + sb.store(&address{array, e.Lbrace, nil}, zeroConst(zt)) } } @@ -1381,8 +1317,13 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero // map[*struct{}]bool{{}: true} // An &-operation may be implied: // map[*struct{}]bool{&struct{}{}: true} + wantAddr := false + if _, ok := unparen(e.Key).(*ast.CompositeLit); ok { + _, wantAddr = deref(t.Key()) + } + var key Value - if _, ok := unparen(e.Key).(*ast.CompositeLit); ok && isPointer(t.Key()) { + if wantAddr { // A CompositeLit never evaluates to a pointer, // so if the type of the location is a pointer, // an &-operation is implied. @@ -1409,7 +1350,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero sb.store(&address{addr: addr, pos: e.Lbrace, expr: e}, m) default: - panic("unexpected CompositeLit type: " + t.String()) + panic("unexpected CompositeLit type: " + typ.String()) } } @@ -1603,13 +1544,13 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl } func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) { - if obj := fn.info.Implicits[cc]; obj != nil { + if obj, ok := fn.info.Implicits[cc].(*types.Var); ok { // In a switch y := x.(type), each case clause // implicitly declares a distinct object y. // In a single-type case, y has that type. // In multi-type cases, 'case nil' and default, // y has the same type as the interface operand. - emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos()) + emitStore(fn, emitLocalVar(fn, obj), x, obj.Pos()) } fn.targets = &targets{ tail: fn.targets, @@ -1758,7 +1699,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { case *ast.AssignStmt: // x := <-states[state].Chan if comm.Tok == token.DEFINE { - fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident)) + emitLocalVar(fn, identVar(fn, comm.Lhs[0].(*ast.Ident))) } x := b.addr(fn, comm.Lhs[0], false) // non-escaping v := emitExtract(fn, sel, r) @@ -1769,7 +1710,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { if len(comm.Lhs) == 2 { // x, ok := ... if comm.Tok == token.DEFINE { - fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident)) + emitLocalVar(fn, identVar(fn, comm.Lhs[1].(*ast.Ident))) } ok := b.addr(fn, comm.Lhs[1], false) // non-escaping ok.store(fn, emitExtract(fn, sel, 1)) @@ -1804,20 +1745,32 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) { // forStmt emits to fn code for the for statement s, optionally // labelled by label. func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) { - // ...init... - // jump loop + // Use forStmtGo122 instead if it applies. + if s.Init != nil { + if assign, ok := s.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE { + afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0 + if afterGo122 { + b.forStmtGo122(fn, s, label) + return + } + } + } + + // ...init... + // jump loop // loop: - // if cond goto body else done + // if cond goto body else done // body: - // ...body... - // jump post - // post: (target of continue) - // ...post... - // jump loop + // ...body... + // jump post + // post: (target of continue) + // ...post... + // jump loop // done: (target of break) if s.Init != nil { b.stmt(fn, s.Init) } + body := fn.newBasicBlock("for.body") done := fn.newBasicBlock("for.done") // target of 'break' loop := body // target of back-edge @@ -1855,35 +1808,199 @@ func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) { fn.currentBlock = done } +// forStmtGo122 emits to fn code for the for statement s, optionally +// labelled by label. s must define its variables. +// +// This allocates once per loop iteration. This is only correct in +// GoVersions >= go1.22. +func (b *builder) forStmtGo122(fn *Function, s *ast.ForStmt, label *lblock) { + // i_outer = alloc[T] + // *i_outer = ...init... // under objects[i] = i_outer + // jump loop + // loop: + // i = phi [head: i_outer, loop: i_next] + // ...cond... // under objects[i] = i + // if cond goto body else done + // body: + // ...body... // under objects[i] = i (same as loop) + // jump post + // post: + // tmp = *i + // i_next = alloc[T] + // *i_next = tmp + // ...post... // under objects[i] = i_next + // goto loop + // done: + + init := s.Init.(*ast.AssignStmt) + startingBlocks := len(fn.Blocks) + + pre := fn.currentBlock // current block before starting + loop := fn.newBasicBlock("for.loop") // target of back-edge + body := fn.newBasicBlock("for.body") + post := fn.newBasicBlock("for.post") // target of 'continue' + done := fn.newBasicBlock("for.done") // target of 'break' + + // For each of the n loop variables, we create five SSA values, + // outer, phi, next, load, and store in pre, loop, and post. + // There is no limit on n. + type loopVar struct { + obj *types.Var + outer *Alloc + phi *Phi + load *UnOp + next *Alloc + store *Store + } + vars := make([]loopVar, len(init.Lhs)) + for i, lhs := range init.Lhs { + v := identVar(fn, lhs.(*ast.Ident)) + typ := fn.typ(v.Type()) + + fn.currentBlock = pre + outer := emitLocal(fn, typ, v.Pos(), v.Name()) + + fn.currentBlock = loop + phi := &Phi{Comment: v.Name()} + phi.pos = v.Pos() + phi.typ = outer.Type() + fn.emit(phi) + + fn.currentBlock = post + // If next is is local, it reuses the address and zeroes the old value so + // load before allocating next. + load := emitLoad(fn, phi) + next := emitLocal(fn, typ, v.Pos(), v.Name()) + store := emitStore(fn, next, load, token.NoPos) + + phi.Edges = []Value{outer, next} // pre edge is emitted before post edge. + + vars[i] = loopVar{v, outer, phi, load, next, store} + } + + // ...init... under fn.objects[v] = i_outer + fn.currentBlock = pre + for _, v := range vars { + fn.vars[v.obj] = v.outer + } + const isDef = false // assign to already-allocated outers + b.assignStmt(fn, init.Lhs, init.Rhs, isDef) + if label != nil { + label._break = done + label._continue = post + } + emitJump(fn, loop) + + // ...cond... under fn.objects[v] = i + fn.currentBlock = loop + for _, v := range vars { + fn.vars[v.obj] = v.phi + } + if s.Cond != nil { + b.cond(fn, s.Cond, body, done) + } else { + emitJump(fn, body) + } + + // ...body... under fn.objects[v] = i + fn.currentBlock = body + fn.targets = &targets{ + tail: fn.targets, + _break: done, + _continue: post, + } + b.stmt(fn, s.Body) + fn.targets = fn.targets.tail + emitJump(fn, post) + + // ...post... under fn.objects[v] = i_next + for _, v := range vars { + fn.vars[v.obj] = v.next + } + fn.currentBlock = post + if s.Post != nil { + b.stmt(fn, s.Post) + } + emitJump(fn, loop) // back-edge + fn.currentBlock = done + + // For each loop variable that does not escape, + // (the common case), fuse its next cells into its + // (local) outer cell as they have disjoint live ranges. + // + // It is sufficient to test whether i_next escapes, + // because its Heap flag will be marked true if either + // the cond or post expression causes i to escape + // (because escape distributes over phi). + var nlocals int + for _, v := range vars { + if !v.next.Heap { + nlocals++ + } + } + if nlocals > 0 { + replace := make(map[Value]Value, 2*nlocals) + dead := make(map[Instruction]bool, 4*nlocals) + for _, v := range vars { + if !v.next.Heap { + replace[v.next] = v.outer + replace[v.phi] = v.outer + dead[v.phi], dead[v.next], dead[v.load], dead[v.store] = true, true, true, true + } + } + + // Replace all uses of i_next and phi with i_outer. + // Referrers have not been built for fn yet so only update Instruction operands. + // We need only look within the blocks added by the loop. + var operands []*Value // recycle storage + for _, b := range fn.Blocks[startingBlocks:] { + for _, instr := range b.Instrs { + operands = instr.Operands(operands[:0]) + for _, ptr := range operands { + k := *ptr + if v := replace[k]; v != nil { + *ptr = v + } + } + } + } + + // Remove instructions for phi, load, and store. + // lift() will remove the unused i_next *Alloc. + isDead := func(i Instruction) bool { return dead[i] } + loop.Instrs = removeInstrsIf(loop.Instrs, isDead) + post.Instrs = removeInstrsIf(post.Instrs, isDead) + } +} + // rangeIndexed emits to fn the header for an integer-indexed loop // over array, *array or slice value x. // The v result is defined only if tv is non-nil. // forPos is the position of the "for" token. func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) { // - // length = len(x) - // index = -1 - // loop: (target of continue) - // index++ - // if index < length goto body else done + // length = len(x) + // index = -1 + // loop: (target of continue) + // index++ + // if index < length goto body else done // body: - // k = index - // v = x[index] - // ...body... - // jump loop - // done: (target of break) + // k = index + // v = x[index] + // ...body... + // jump loop + // done: (target of break) // Determine number of iterations. var length Value - if arr, ok := deref(x.Type()).Underlying().(*types.Array); ok { + dt, _ := deref(x.Type()) + if arr, ok := typeparams.CoreType(dt).(*types.Array); ok { // For array or *array, the number of iterations is // known statically thanks to the type. We avoid a // data dependence upon x, permitting later dead-code // elimination if x is pure, static unrolling, etc. // Ranging over a nil *array may have >0 iterations. // We still generate code for x, in case it has effects. - // - // TypeParams do not have constant length. Use underlying instead of core type. length = intConst(arr.Len()) } else { // length = len(x). @@ -1894,7 +2011,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P length = fn.emit(&c) } - index := fn.addLocal(tInt, token.NoPos) + index := emitLocal(fn, tInt, token.NoPos, "rangeindex") emitStore(fn, index, intConst(-1), pos) loop = fn.newBasicBlock("rangeindex.loop") @@ -1957,16 +2074,16 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P // if the respective component is not wanted. func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) { // - // it = range x + // it = range x // loop: (target of continue) - // okv = next it (ok, key, value) - // ok = extract okv #0 - // if ok goto body else done + // okv = next it (ok, key, value) + // ok = extract okv #0 + // if ok goto body else done // body: - // k = extract okv #1 - // v = extract okv #2 - // ...body... - // jump loop + // k = extract okv #1 + // v = extract okv #2 + // ...body... + // jump loop // done: (target of break) // @@ -2019,13 +2136,13 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token. func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) { // // loop: (target of continue) - // ko = <-x (key, ok) - // ok = extract ko #1 - // if ok goto body else done + // ko = <-x (key, ok) + // ok = extract ko #1 + // if ok goto body else done // body: - // k = extract ko #0 - // ... - // goto loop + // k = extract ko #0 + // ...body... + // goto loop // done: (target of break) loop = fn.newBasicBlock("rangechan.loop") @@ -2052,6 +2169,57 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) return } +// rangeInt emits to fn the header for a range loop with an integer operand. +// tk is the key value's type, or nil if the k result is not wanted. +// pos is the position of the "for" token. +func (b *builder) rangeInt(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) { + // + // iter = 0 + // if 0 < x goto body else done + // loop: (target of continue) + // iter++ + // if iter < x goto body else done + // body: + // k = x + // ...body... + // jump loop + // done: (target of break) + + if isUntyped(x.Type()) { + x = emitConv(fn, x, tInt) + } + + T := x.Type() + iter := emitLocal(fn, T, token.NoPos, "rangeint.iter") + // x may be unsigned. Avoid initializing x to -1. + + body := fn.newBasicBlock("rangeint.body") + done = fn.newBasicBlock("rangeint.done") + emitIf(fn, emitCompare(fn, token.LSS, zeroConst(T), x, token.NoPos), body, done) + + loop = fn.newBasicBlock("rangeint.loop") + fn.currentBlock = loop + + incr := &BinOp{ + Op: token.ADD, + X: emitLoad(fn, iter), + Y: emitConv(fn, vOne, T), + } + incr.setType(T) + emitStore(fn, iter, fn.emit(incr), pos) + emitIf(fn, emitCompare(fn, token.LSS, incr, x, token.NoPos), body, done) + fn.currentBlock = body + + if tk != nil { + // Integer types (int, uint8, etc.) are named and + // we know that k is assignable to x when tk != nil. + // This implies tk and T are identical so no conversion is needed. + k = emitLoad(fn, iter) + } + + return +} + // rangeStmt emits to fn code for the range statement s, optionally // labelled by label. func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { @@ -2063,21 +2231,26 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { tv = fn.typeOf(s.Value) } - // If iteration variables are defined (:=), this - // occurs once outside the loop. - // - // Unlike a short variable declaration, a RangeStmt - // using := never redeclares an existing variable; it - // always creates a new one. - if s.Tok == token.DEFINE { + // create locals for s.Key and s.Value. + createVars := func() { + // Unlike a short variable declaration, a RangeStmt + // using := never redeclares an existing variable; it + // always creates a new one. if tk != nil { - fn.addLocalForIdent(s.Key.(*ast.Ident)) + emitLocalVar(fn, identVar(fn, s.Key.(*ast.Ident))) } if tv != nil { - fn.addLocalForIdent(s.Value.(*ast.Ident)) + emitLocalVar(fn, identVar(fn, s.Value.(*ast.Ident))) } } + afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0 + if s.Tok == token.DEFINE && !afterGo122 { + // pre-go1.22: If iteration variables are defined (:=), this + // occurs once outside the loop. + createVars() + } + x := b.expr(fn, s.X) var k, v Value @@ -2089,13 +2262,30 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) { case *types.Chan: k, loop, done = b.rangeChan(fn, x, tk, s.For) - case *types.Map, *types.Basic: // string + case *types.Map: k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) + case *types.Basic: + switch { + case rt.Info()&types.IsString != 0: + k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For) + + case rt.Info()&types.IsInteger != 0: + k, loop, done = b.rangeInt(fn, x, tk, s.For) + + default: + panic("Cannot range over basic type: " + rt.String()) + } + default: panic("Cannot range over: " + rt.String()) } + if s.Tok == token.DEFINE && afterGo122 { + // go1.22: If iteration variables are defined (:=), this occurs inside the loop. + createVars() + } + // Evaluate both LHS expressions before we update either. var kl, vl lvalue if tk != nil { @@ -2319,73 +2509,71 @@ start: } } +// A buildFunc is a strategy for building the SSA body for a function. +type buildFunc = func(*builder, *Function) + +// iterate causes all created but unbuilt functions to be built. As +// this may create new methods, the process is iterated until it +// converges. +func (b *builder) iterate() { + for ; b.finished < b.created.Len(); b.finished++ { + fn := b.created.At(b.finished) + b.buildFunction(fn) + } +} + // buildFunction builds SSA code for the body of function fn. Idempotent. func (b *builder) buildFunction(fn *Function) { - if !fn.built { + if fn.build != nil { assert(fn.parent == nil, "anonymous functions should not be built by buildFunction()") - b.buildFunctionBody(fn) + + if fn.Prog.mode&LogSource != 0 { + defer logStack("build %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))() + } + fn.build(b, fn) fn.done() } } -// buildFunctionBody builds SSA code for the body of function fn. -// -// fn is not done building until fn.done() is called. -func (b *builder) buildFunctionBody(fn *Function) { - // TODO(taking): see if this check is reachable. - if fn.Blocks != nil { - return // building already started +// buildParamsOnly builds fn.Params from fn.Signature, but does not build fn.Body. +func (b *builder) buildParamsOnly(fn *Function) { + // For external (C, asm) functions or functions loaded from + // export data, we must set fn.Params even though there is no + // body code to reference them. + if recv := fn.Signature.Recv(); recv != nil { + fn.addParamVar(recv) } + params := fn.Signature.Params() + for i, n := 0, params.Len(); i < n; i++ { + fn.addParamVar(params.At(i)) + } +} - var recvField *ast.FieldList - var body *ast.BlockStmt - var functype *ast.FuncType - switch n := fn.syntax.(type) { - case nil: - if fn.Params != nil { - return // not a Go source function. (Synthetic, or from object file.) - } +// buildFromSyntax builds fn.Body from fn.syntax, which must be non-nil. +func (b *builder) buildFromSyntax(fn *Function) { + var ( + recvField *ast.FieldList + body *ast.BlockStmt + functype *ast.FuncType + ) + switch syntax := fn.syntax.(type) { case *ast.FuncDecl: - functype = n.Type - recvField = n.Recv - body = n.Body + functype = syntax.Type + recvField = syntax.Recv + body = syntax.Body + if body == nil { + b.buildParamsOnly(fn) // no body (non-Go function) + return + } case *ast.FuncLit: - functype = n.Type - body = n.Body + functype = syntax.Type + body = syntax.Body + case nil: + panic("no syntax") default: - panic(n) - } - - if body == nil { - // External function. - if fn.Params == nil { - // This condition ensures we add a non-empty - // params list once only, but we may attempt - // the degenerate empty case repeatedly. - // TODO(adonovan): opt: don't do that. - - // We set Function.Params even though there is no body - // code to reference them. This simplifies clients. - if recv := fn.Signature.Recv(); recv != nil { - fn.addParamObj(recv) - } - params := fn.Signature.Params() - for i, n := 0, params.Len(); i < n; i++ { - fn.addParamObj(params.At(i)) - } - } - return + panic(syntax) // unexpected syntax } - // Build instantiation wrapper around generic body? - if fn.topLevelOrigin != nil && fn.subst == nil { - buildInstantiationWrapper(fn) - return - } - - if fn.Prog.mode&LogSource != 0 { - defer logStack("build function %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))() - } fn.startBody() fn.createSyntacticParams(recvField, functype) b.stmt(fn, body) @@ -2403,45 +2591,17 @@ func (b *builder) buildFunctionBody(fn *Function) { fn.finishBody() } -// buildCreated does the BUILD phase for each function created by builder that is not yet BUILT. -// Functions are built using buildFunction. +// addRuntimeType records t as a runtime type, +// along with all types derivable from it using reflection. // -// May add types that require runtime type information to builder. -func (b *builder) buildCreated() { - for ; b.finished < b.created.Len(); b.finished++ { - fn := b.created.At(b.finished) - b.buildFunction(fn) - } -} - -// Adds any needed runtime type information for the created functions. -// -// May add newly CREATEd functions that may need to be built or runtime type information. -// -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) -func (b *builder) needsRuntimeTypes() { - if b.created.Len() == 0 { - return - } - prog := b.created.At(0).Prog - - var rtypes []types.Type - for ; b.rtypes < b.finished; b.rtypes++ { - fn := b.created.At(b.rtypes) - rtypes = append(rtypes, mayNeedRuntimeTypes(fn)...) - } - - // Calling prog.needMethodsOf(T) on a basic type T is a no-op. - // Filter out the basic types to reduce acquiring prog.methodsMu. - rtypes = nonbasicTypes(rtypes) - - for _, T := range rtypes { - prog.needMethodsOf(T, b.created) - } -} - -func (b *builder) done() bool { - return b.rtypes >= b.created.Len() +// Acquires prog.runtimeTypesMu. +func addRuntimeType(prog *Program, t types.Type) { + prog.runtimeTypesMu.Lock() + defer prog.runtimeTypesMu.Unlock() + forEachReachable(&prog.MethodSets, t, func(t types.Type) bool { + prev, _ := prog.runtimeTypes.Set(t, true).(bool) + return !prev // already seen? + }) } // Build calls Package.Build for each package in prog. @@ -2469,9 +2629,11 @@ func (prog *Program) Build() { // Build builds SSA code for all functions and vars in package p. // -// Precondition: CreatePackage must have been called for all of p's -// direct imports (and hence its direct imports must have been -// error-free). +// CreatePackage must have been called for all of p's direct imports +// (and hence its direct imports must have been error-free). It is not +// necessary to call CreatePackage for indirect dependencies. +// Functions will be created for all necessary methods in those +// packages on demand. // // Build is idempotent and thread-safe. func (p *Package) Build() { p.buildOnce.Do(p.build) } @@ -2480,45 +2642,39 @@ func (p *Package) build() { if p.info == nil { return // synthetic package, e.g. "testmain" } - - // Ensure we have runtime type info for all exported members. - // Additionally filter for just concrete types that can be runtime types. - // - // TODO(adonovan): ideally belongs in memberFromObject, but - // that would require package creation in topological order. - for name, mem := range p.Members { - isGround := func(m Member) bool { - switch m := m.(type) { - case *Type: - named, _ := m.Type().(*types.Named) - return named == nil || typeparams.ForNamed(named) == nil - case *Function: - return m.typeparams.Len() == 0 - } - return true // *NamedConst, *Global - } - if ast.IsExported(name) && isGround(mem) { - p.Prog.needMethodsOf(mem.Type(), &p.created) - } - } if p.Prog.mode&LogSource != 0 { defer logStack("build %s", p)() } b := builder{created: &p.created} - init := p.init - init.startBody() + b.iterate() + + // We no longer need transient information: ASTs or go/types deductions. + p.info = nil + p.created = nil + p.files = nil + p.initVersion = nil + + if p.Prog.mode&SanityCheckFunctions != 0 { + sanityCheckPackage(p) + } +} + +// buildPackageInit builds fn.Body for the synthetic package initializer. +func (b *builder) buildPackageInit(fn *Function) { + p := fn.Pkg + fn.startBody() var done *BasicBlock if p.Prog.mode&BareInits == 0 { // Make init() skip if package is already initialized. initguard := p.Var("init$guard") - doinit := init.newBasicBlock("init.start") - done = init.newBasicBlock("init.done") - emitIf(init, emitLoad(init, initguard), done, doinit) - init.currentBlock = doinit - emitStore(init, initguard, vTrue, token.NoPos) + doinit := fn.newBasicBlock("init.start") + done = fn.newBasicBlock("init.done") + emitIf(fn, emitLoad(fn, initguard), done, doinit) + fn.currentBlock = doinit + emitStore(fn, initguard, vTrue, token.NoPos) // Call the init() function of each package we import. for _, pkg := range p.Pkg.Imports() { @@ -2528,9 +2684,9 @@ func (p *Package) build() { } var v Call v.Call.Value = prereq.init - v.Call.pos = init.pos + v.Call.pos = fn.pos v.setType(types.NewTuple()) - init.emit(&v) + fn.emit(&v) } } @@ -2538,11 +2694,18 @@ func (p *Package) build() { if len(p.info.InitOrder) > 0 && len(p.files) == 0 { panic("no source files provided for package. cannot initialize globals") } + for _, varinit := range p.info.InitOrder { - if init.Prog.mode&LogSource != 0 { + if fn.Prog.mode&LogSource != 0 { fmt.Fprintf(os.Stderr, "build global initializer %v @ %s\n", varinit.Lhs, p.Prog.Fset.Position(varinit.Rhs.Pos())) } + // Initializers for global vars are evaluated in dependency + // order, but may come from arbitrary files of the package + // with different versions, so we transiently update + // fn.goversion for each one. (Since init is a synthetic + // function it has no syntax of its own that needs a version.) + fn.goversion = p.initVersion[varinit.Rhs] if len(varinit.Lhs) == 1 { // 1:1 initialization: var x, y = a(), b() var lval lvalue @@ -2551,28 +2714,33 @@ func (p *Package) build() { } else { lval = blank{} } - b.assign(init, lval, varinit.Rhs, true, nil) + b.assign(fn, lval, varinit.Rhs, true, nil) } else { // n:1 initialization: var x, y := f() - tuple := b.exprN(init, varinit.Rhs) + tuple := b.exprN(fn, varinit.Rhs) for i, v := range varinit.Lhs { if v.Name() == "_" { continue } - emitStore(init, p.objects[v].(*Global), emitExtract(init, tuple, i), v.Pos()) + emitStore(fn, p.objects[v].(*Global), emitExtract(fn, tuple, i), v.Pos()) } } } + // The rest of the init function is synthetic: + // no syntax, info, goversion. + fn.info = nil + fn.goversion = "" + // Call all of the declared init() functions in source order. for _, file := range p.files { for _, decl := range file.Decls { if decl, ok := decl.(*ast.FuncDecl); ok { id := decl.Name if !isBlankIdent(id) && id.Name == "init" && decl.Recv == nil { - fn := p.objects[p.info.Defs[id]].(*Function) + declaredInit := p.objects[p.info.Defs[id]].(*Function) var v Call - v.Call.Value = fn + v.Call.Value = declaredInit v.setType(types.NewTuple()) p.init.emit(&v) } @@ -2582,35 +2750,9 @@ func (p *Package) build() { // Finish up init(). if p.Prog.mode&BareInits == 0 { - emitJump(init, done) - init.currentBlock = done - } - init.emit(new(Return)) - init.finishBody() - init.done() - - // Build all CREATEd functions and add runtime types. - // These Functions include package-level functions, init functions, methods, and synthetic (including unreachable/blank ones). - // Builds any functions CREATEd while building this package. - // - // Initially the created functions for the package are: - // [init, decl0, ... , declN] - // Where decl0, ..., declN are declared functions in source order, but it's not significant. - // - // As these are built, more functions (function literals, wrappers, etc.) can be CREATEd. - // Iterate until we reach a fixed point. - // - // Wait for init() to be BUILT as that cannot be built by buildFunction(). - // - for !b.done() { - b.buildCreated() // build any CREATEd and not BUILT function. May add runtime types. - b.needsRuntimeTypes() // Add all of the runtime type information. May CREATE Functions. - } - - p.info = nil // We no longer need ASTs or go/types deductions. - p.created = nil // We no longer need created functions. - - if p.Prog.mode&SanityCheckFunctions != 0 { - sanityCheckPackage(p) + emitJump(fn, done) + fn.currentBlock = done } + fn.emit(new(Return)) + fn.finishBody() } diff --git a/vendor/golang.org/x/tools/go/ssa/const.go b/vendor/golang.org/x/tools/go/ssa/const.go index 4a51a2cb4..2a6ac5882 100644 --- a/vendor/golang.org/x/tools/go/ssa/const.go +++ b/vendor/golang.org/x/tools/go/ssa/const.go @@ -125,7 +125,7 @@ func zeroString(t types.Type, from *types.Package) string { components[i] = zeroString(t.At(i).Type(), from) } return "(" + strings.Join(components, ", ") + ")" - case *typeparams.TypeParam: + case *types.TypeParam: return "*new(" + relType(t, from) + ")" } panic(fmt.Sprint("zeroString: unexpected ", t)) diff --git a/vendor/golang.org/x/tools/go/ssa/coretype.go b/vendor/golang.org/x/tools/go/ssa/coretype.go index 128d61e42..88136b438 100644 --- a/vendor/golang.org/x/tools/go/ssa/coretype.go +++ b/vendor/golang.org/x/tools/go/ssa/coretype.go @@ -40,19 +40,19 @@ func isBytestring(T types.Type) bool { } // termList is a list of types. -type termList []*typeparams.Term // type terms of the type set +type termList []*types.Term // type terms of the type set func (s termList) Len() int { return len(s) } func (s termList) At(i int) types.Type { return s[i].Type() } // typeSetOf returns the type set of typ. Returns an empty typeset on an error. func typeSetOf(typ types.Type) termList { // This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on. - var terms []*typeparams.Term + var terms []*types.Term var err error switch typ := typ.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: terms, err = typeparams.StructuralTerms(typ) - case *typeparams.Union: + case *types.Union: terms, err = typeparams.UnionTermSet(typ) case *types.Interface: terms, err = typeparams.InterfaceTermSet(typ) @@ -60,7 +60,7 @@ func typeSetOf(typ types.Type) termList { // Common case. // Specializing the len=1 case to avoid a slice // had no measurable space/time benefit. - terms = []*typeparams.Term{typeparams.NewTerm(false, typ)} + terms = []*types.Term{types.NewTerm(false, typ)} } if err != nil { diff --git a/vendor/golang.org/x/tools/go/ssa/create.go b/vendor/golang.org/x/tools/go/ssa/create.go index ccb20e796..c4da35d0b 100644 --- a/vendor/golang.org/x/tools/go/ssa/create.go +++ b/vendor/golang.org/x/tools/go/ssa/create.go @@ -15,41 +15,43 @@ import ( "os" "sync" - "golang.org/x/tools/go/types/typeutil" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) // NewProgram returns a new SSA Program. // // mode controls diagnostics and checking during SSA construction. +// +// To construct an SSA program: +// +// - Call NewProgram to create an empty Program. +// - Call CreatePackage providing typed syntax for each package +// you want to build, and call it with types but not +// syntax for each of those package's direct dependencies. +// - Call [Package.Build] on each syntax package you wish to build, +// or [Program.Build] to build all of them. +// +// See the Example tests for simple examples. func NewProgram(fset *token.FileSet, mode BuilderMode) *Program { - prog := &Program{ + return &Program{ Fset: fset, imported: make(map[string]*Package), packages: make(map[*types.Package]*Package), - thunks: make(map[selectionKey]*Function), - bounds: make(map[boundsKey]*Function), mode: mode, canon: newCanonizer(), - ctxt: typeparams.NewContext(), - instances: make(map[*Function]*instanceSet), + ctxt: types.NewContext(), parameterized: tpWalker{seen: make(map[types.Type]bool)}, } - - h := typeutil.MakeHasher() // protected by methodsMu, in effect - prog.methodSets.SetHasher(h) - prog.runtimeTypes.SetHasher(h) - - return prog } // memberFromObject populates package pkg with a member for the // typechecker object obj. // // For objects from Go source code, syntax is the associated syntax -// tree (for funcs and vars only); it will be used during the build +// tree (for funcs and vars only) and goversion defines the +// appropriate interpretation; they will be used during the build // phase. -func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { +func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion string) { name := obj.Name() switch obj := obj.(type) { case *types.Builtin: @@ -58,9 +60,11 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { } case *types.TypeName: - pkg.Members[name] = &Type{ - object: obj, - pkg: pkg, + if name != "_" { + pkg.Members[name] = &Type{ + object: obj, + pkg: pkg, + } } case *types.Const: @@ -70,7 +74,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pkg: pkg, } pkg.objects[obj] = c - pkg.Members[name] = c + if name != "_" { + pkg.Members[name] = c + } case *types.Var: g := &Global{ @@ -81,7 +87,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pos: obj.Pos(), } pkg.objects[obj] = g - pkg.Members[name] = g + if name != "_" { + pkg.Members[name] = g + } case *types.Func: sig := obj.Type().(*types.Signature) @@ -89,36 +97,10 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { pkg.ninit++ name = fmt.Sprintf("init#%d", pkg.ninit) } - - // Collect type parameters if this is a generic function/method. - var tparams *typeparams.TypeParamList - if rtparams := typeparams.RecvTypeParams(sig); rtparams.Len() > 0 { - tparams = rtparams - } else if sigparams := typeparams.ForSignature(sig); sigparams.Len() > 0 { - tparams = sigparams - } - - fn := &Function{ - name: name, - object: obj, - Signature: sig, - syntax: syntax, - pos: obj.Pos(), - Pkg: pkg, - Prog: pkg.Prog, - typeparams: tparams, - info: pkg.info, - } - pkg.created.Add(fn) - if syntax == nil { - fn.Synthetic = "loaded from gc object file" - } - if tparams.Len() > 0 { - fn.Prog.createInstanceSet(fn) - } - + fn := createFunction(pkg.Prog, obj, name, syntax, pkg.info, goversion, &pkg.created) + fn.Pkg = pkg pkg.objects[obj] = fn - if sig.Recv() == nil { + if name != "_" && sig.Recv() == nil { pkg.Members[name] = fn // package-level function } @@ -127,45 +109,79 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) { } } +// createFunction creates a function or method. It supports both +// CreatePackage (with or without syntax) and the on-demand creation +// of methods in non-created packages based on their types.Func. +func createFunction(prog *Program, obj *types.Func, name string, syntax ast.Node, info *types.Info, goversion string, cr *creator) *Function { + sig := obj.Type().(*types.Signature) + + // Collect type parameters. + var tparams *types.TypeParamList + if rtparams := sig.RecvTypeParams(); rtparams.Len() > 0 { + tparams = rtparams // method of generic type + } else if sigparams := sig.TypeParams(); sigparams.Len() > 0 { + tparams = sigparams // generic function + } + + /* declared function/method (from syntax or export data) */ + fn := &Function{ + name: name, + object: obj, + Signature: sig, + build: (*builder).buildFromSyntax, + syntax: syntax, + info: info, + goversion: goversion, + pos: obj.Pos(), + Pkg: nil, // may be set by caller + Prog: prog, + typeparams: tparams, + } + if fn.syntax == nil { + fn.Synthetic = "from type information" + fn.build = (*builder).buildParamsOnly + } + if tparams.Len() > 0 { + fn.generic = new(generic) + } + cr.Add(fn) + return fn +} + // membersFromDecl populates package pkg with members for each // typechecker object (var, func, const or type) associated with the // specified decl. -func membersFromDecl(pkg *Package, decl ast.Decl) { +func membersFromDecl(pkg *Package, decl ast.Decl, goversion string) { switch decl := decl.(type) { case *ast.GenDecl: // import, const, type or var switch decl.Tok { case token.CONST: for _, spec := range decl.Specs { for _, id := range spec.(*ast.ValueSpec).Names { - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], nil) - } + memberFromObject(pkg, pkg.info.Defs[id], nil, "") } } case token.VAR: for _, spec := range decl.Specs { + for _, rhs := range spec.(*ast.ValueSpec).Values { + pkg.initVersion[rhs] = goversion + } for _, id := range spec.(*ast.ValueSpec).Names { - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], spec) - } + memberFromObject(pkg, pkg.info.Defs[id], spec, goversion) } } case token.TYPE: for _, spec := range decl.Specs { id := spec.(*ast.TypeSpec).Name - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], nil) - } + memberFromObject(pkg, pkg.info.Defs[id], nil, "") } } case *ast.FuncDecl: id := decl.Name - if !isBlankIdent(id) { - memberFromObject(pkg, pkg.info.Defs[id], decl) - } + memberFromObject(pkg, pkg.info.Defs[id], decl, goversion) } } @@ -182,7 +198,7 @@ func (c *creator) Add(fn *Function) { func (c *creator) At(i int) *Function { return (*c)[i] } func (c *creator) Len() int { return len(*c) } -// CreatePackage constructs and returns an SSA Package from the +// CreatePackage creates and returns an SSA Package from the // specified type-checked, error-free file ASTs, and populates its // Members mapping. // @@ -190,36 +206,48 @@ func (c *creator) Len() int { return len(*c) } // subsequent call to ImportedPackage(pkg.Path()). // // The real work of building SSA form for each function is not done -// until a subsequent call to Package.Build(). +// until a subsequent call to Package.Build. +// +// CreatePackage should not be called after building any package in +// the program. func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package { + // TODO(adonovan): assert that no package has yet been built. + if pkg == nil { + panic("nil pkg") // otherwise pkg.Scope below returns types.Universe! + } p := &Package{ Prog: prog, Members: make(map[string]Member), objects: make(map[types.Object]Member), Pkg: pkg, - info: info, // transient (CREATE and BUILD phases) - files: files, // transient (CREATE and BUILD phases) + syntax: info != nil, + // transient values (cleared after Package.Build) + info: info, + files: files, + initVersion: make(map[ast.Expr]string), } - // Add init() function. + /* synthesized package initializer */ p.init = &Function{ name: "init", Signature: new(types.Signature), Synthetic: "package initializer", Pkg: p, Prog: prog, + build: (*builder).buildPackageInit, info: p.info, + goversion: "", // See Package.build for details. } p.Members[p.init.name] = p.init p.created.Add(p.init) - // CREATE phase. // Allocate all package members: vars, funcs, consts and types. if len(files) > 0 { // Go source package. for _, file := range files { + goversion := versions.Lang(versions.FileVersions(p.info, file)) for _, decl := range file.Decls { - membersFromDecl(p, decl) + membersFromDecl(p, decl, goversion) } } } else { @@ -229,11 +257,11 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info * scope := p.Pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) - memberFromObject(p, obj, nil) + memberFromObject(p, obj, nil, "") if obj, ok := obj.(*types.TypeName); ok { if named, ok := obj.Type().(*types.Named); ok { for i, n := 0, named.NumMethods(); i < n; i++ { - memberFromObject(p, named.Method(i), nil) + memberFromObject(p, named.Method(i), nil, "") } } } @@ -271,8 +299,8 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info * // printMu serializes printing of Packages/Functions to stdout. var printMu sync.Mutex -// AllPackages returns a new slice containing all packages in the -// program prog in unspecified order. +// AllPackages returns a new slice containing all packages created by +// prog.CreatePackage in in unspecified order. func (prog *Program) AllPackages() []*Package { pkgs := make([]*Package, 0, len(prog.packages)) for _, pkg := range prog.packages { @@ -294,6 +322,10 @@ func (prog *Program) AllPackages() []*Package { // false---yet this function remains very convenient. // Clients should use (*Program).Package instead where possible. // SSA doesn't really need a string-keyed map of packages. +// +// Furthermore, the graph of packages may contain multiple variants +// (e.g. "p" vs "p as compiled for q.test"), and each has a different +// view of its dependencies. func (prog *Program) ImportedPackage(path string) *Package { return prog.imported[path] } diff --git a/vendor/golang.org/x/tools/go/ssa/doc.go b/vendor/golang.org/x/tools/go/ssa/doc.go index afda476b3..3310b5509 100644 --- a/vendor/golang.org/x/tools/go/ssa/doc.go +++ b/vendor/golang.org/x/tools/go/ssa/doc.go @@ -7,8 +7,6 @@ // static single-assignment (SSA) form intermediate representation // (IR) for the bodies of functions. // -// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE. -// // For an introduction to SSA form, see // http://en.wikipedia.org/wiki/Static_single_assignment_form. // This page provides a broader reading list: @@ -21,15 +19,15 @@ // All looping, branching and switching constructs are replaced with // unstructured control flow. Higher-level control flow constructs // such as multi-way branch can be reconstructed as needed; see -// ssautil.Switches() for an example. +// [golang.org/x/tools/go/ssa/ssautil.Switches] for an example. // // The simplest way to create the SSA representation of a package is -// to load typed syntax trees using golang.org/x/tools/go/packages, then -// invoke the ssautil.Packages helper function. See Example_loadPackages -// and Example_loadWholeProgram for examples. -// The resulting ssa.Program contains all the packages and their +// to load typed syntax trees using [golang.org/x/tools/go/packages], then +// invoke the [golang.org/x/tools/go/ssa/ssautil.Packages] helper function. +// (See the package-level Examples named LoadPackages and LoadWholeProgram.) +// The resulting [ssa.Program] contains all the packages and their // members, but SSA code is not created for function bodies until a -// subsequent call to (*Package).Build or (*Program).Build. +// subsequent call to [Package.Build] or [Program.Build]. // // The builder initially builds a naive SSA form in which all local // variables are addresses of stack locations with explicit loads and @@ -41,13 +39,13 @@ // // The primary interfaces of this package are: // -// - Member: a named member of a Go package. -// - Value: an expression that yields a value. -// - Instruction: a statement that consumes values and performs computation. -// - Node: a Value or Instruction (emphasizing its membership in the SSA value graph) +// - [Member]: a named member of a Go package. +// - [Value]: an expression that yields a value. +// - [Instruction]: a statement that consumes values and performs computation. +// - [Node]: a [Value] or [Instruction] (emphasizing its membership in the SSA value graph) // -// A computation that yields a result implements both the Value and -// Instruction interfaces. The following table shows for each +// A computation that yields a result implements both the [Value] and +// [Instruction] interfaces. The following table shows for each // concrete type which of these interfaces it implements. // // Value? Instruction? Member? @@ -66,7 +64,6 @@ // *FieldAddr ✔ ✔ // *FreeVar ✔ // *Function ✔ ✔ (func) -// *GenericConvert ✔ ✔ // *Global ✔ ✔ (var) // *Go ✔ // *If ✔ @@ -80,6 +77,7 @@ // *MakeMap ✔ ✔ // *MakeSlice ✔ ✔ // *MapUpdate ✔ +// *MultiConvert ✔ ✔ // *NamedConst ✔ (const) // *Next ✔ ✔ // *Panic ✔ @@ -97,15 +95,15 @@ // *TypeAssert ✔ ✔ // *UnOp ✔ ✔ // -// Other key types in this package include: Program, Package, Function -// and BasicBlock. +// Other key types in this package include: [Program], [Package], [Function] +// and [BasicBlock]. // // The program representation constructed by this package is fully // resolved internally, i.e. it does not rely on the names of Values, // Packages, Functions, Types or BasicBlocks for the correct // interpretation of the program. Only the identities of objects and // the topology of the SSA and type graphs are semantically -// significant. (There is one exception: Ids, used to identify field +// significant. (There is one exception: [types.Id] values, which identify field // and method names, contain strings.) Avoidance of name-based // operations simplifies the implementation of subsequent passes and // can make them very efficient. Many objects are nonetheless named @@ -113,11 +111,9 @@ // either accurate or unambiguous. The public API exposes a number of // name-based maps for client convenience. // -// The ssa/ssautil package provides various utilities that depend only -// on the public API of this package. -// -// TODO(adonovan): Consider the exceptional control-flow implications -// of defer and recover(). +// The [golang.org/x/tools/go/ssa/ssautil] package provides various +// helper functions, for example to simplify loading a Go program into +// SSA form. // // TODO(adonovan): write a how-to document for all the various cases // of trying to determine corresponding elements across the four diff --git a/vendor/golang.org/x/tools/go/ssa/emit.go b/vendor/golang.org/x/tools/go/ssa/emit.go index 1731c7975..d77b4407a 100644 --- a/vendor/golang.org/x/tools/go/ssa/emit.go +++ b/vendor/golang.org/x/tools/go/ssa/emit.go @@ -11,25 +11,60 @@ import ( "go/ast" "go/token" "go/types" - - "golang.org/x/tools/internal/typeparams" ) -// emitNew emits to f a new (heap Alloc) instruction allocating an -// object of type typ. pos is the optional source location. -func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc { - v := &Alloc{Heap: true} +// emitAlloc emits to f a new Alloc instruction allocating a variable +// of type typ. +// +// The caller must set Alloc.Heap=true (for an heap-allocated variable) +// or add the Alloc to f.Locals (for a frame-allocated variable). +// +// During building, a variable in f.Locals may have its Heap flag +// set when it is discovered that its address is taken. +// These Allocs are removed from f.Locals at the end. +// +// The builder should generally call one of the emit{New,Local,LocalVar} wrappers instead. +func emitAlloc(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc { + v := &Alloc{Comment: comment} v.setType(types.NewPointer(typ)) v.setPos(pos) f.emit(v) return v } +// emitNew emits to f a new Alloc instruction heap-allocating a +// variable of type typ. pos is the optional source location. +func emitNew(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc { + alloc := emitAlloc(f, typ, pos, comment) + alloc.Heap = true + return alloc +} + +// emitLocal creates a local var for (t, pos, comment) and +// emits an Alloc instruction for it. +// +// (Use this function or emitNew for synthetic variables; +// for source-level variables, use emitLocalVar.) +func emitLocal(f *Function, t types.Type, pos token.Pos, comment string) *Alloc { + local := emitAlloc(f, t, pos, comment) + f.Locals = append(f.Locals, local) + return local +} + +// emitLocalVar creates a local var for v and emits an Alloc instruction for it. +// Subsequent calls to f.lookup(v) return it. +// It applies the appropriate generic instantiation to the type. +func emitLocalVar(f *Function, v *types.Var) *Alloc { + alloc := emitLocal(f, f.typ(v.Type()), v.Pos(), v.Name()) + f.vars[v] = alloc + return alloc +} + // emitLoad emits to f an instruction to load the address addr into a // new temporary, and returns the value so defined. func emitLoad(f *Function, addr Value) *UnOp { v := &UnOp{Op: token.MUL, X: addr} - v.setType(deref(typeparams.CoreType(addr.Type()))) + v.setType(mustDeref(addr.Type())) f.emit(v) return v } @@ -103,7 +138,7 @@ func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token. } // emitCompare emits to f code compute the boolean result of -// comparison comparison 'x op y'. +// comparison 'x op y'. func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value { xt := x.Type().Underlying() yt := y.Type().Underlying() @@ -150,7 +185,7 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value { // Precondition: neither argument is a named type. func isValuePreserving(ut_src, ut_dst types.Type) bool { // Identical underlying types? - if structTypesIdentical(ut_dst, ut_src) { + if types.IdenticalIgnoreTags(ut_dst, ut_src) { return true } @@ -208,6 +243,13 @@ func emitConv(f *Function, val Value, typ types.Type) Value { val = emitConv(f, val, types.Default(ut_src)) } + // Record the types of operands to MakeInterface, if + // non-parameterized, as they are the set of runtime types. + t := val.Type() + if f.typeparams.Len() == 0 || !f.Prog.parameterized.isParameterized(t) { + addRuntimeType(f.Prog, t) + } + mi := &MakeInterface{X: val} mi.setType(typ) return f.emit(mi) @@ -372,9 +414,10 @@ func emitTypeCoercion(f *Function, v Value, typ types.Type) Value { // emitStore emits to f an instruction to store value val at location // addr, applying implicit conversions as required by assignability rules. func emitStore(f *Function, addr, val Value, pos token.Pos) *Store { + typ := mustDeref(addr.Type()) s := &Store{ Addr: addr, - Val: emitConv(f, val, deref(addr.Type())), + Val: emitConv(f, val, typ), pos: pos, } f.emit(s) @@ -477,9 +520,8 @@ func emitTailCall(f *Function, call *Call) { // value of a field. func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) Value { for _, index := range indices { - fld := typeparams.CoreType(deref(v.Type())).(*types.Struct).Field(index) - - if isPointer(v.Type()) { + if st, vptr := deref(v.Type()); vptr { + fld := fieldOf(st, index) instr := &FieldAddr{ X: v, Field: index, @@ -488,10 +530,11 @@ func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) instr.setType(types.NewPointer(fld.Type())) v = f.emit(instr) // Load the field's value iff indirectly embedded. - if isPointer(fld.Type()) { + if _, fldptr := deref(fld.Type()); fldptr { v = emitLoad(f, v) } } else { + fld := fieldOf(v.Type(), index) instr := &Field{ X: v, Field: index, @@ -511,8 +554,8 @@ func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) // field's value. // Ident id is used for position and debug info. func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value { - fld := typeparams.CoreType(deref(v.Type())).(*types.Struct).Field(index) - if isPointer(v.Type()) { + if st, vptr := deref(v.Type()); vptr { + fld := fieldOf(st, index) instr := &FieldAddr{ X: v, Field: index, @@ -525,6 +568,7 @@ func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast. v = emitLoad(f, v) } } else { + fld := fieldOf(v.Type(), index) instr := &Field{ X: v, Field: index, @@ -537,17 +581,6 @@ func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast. return v } -// zeroValue emits to f code to produce a zero value of type t, -// and returns it. -func zeroValue(f *Function, t types.Type) Value { - switch t.Underlying().(type) { - case *types.Struct, *types.Array: - return emitLoad(f, f.addLocal(t, token.NoPos)) - default: - return zeroConst(t) - } -} - // createRecoverBlock emits to f a block of code to return after a // recovered panic, and sets f.Recover to it. // @@ -577,7 +610,7 @@ func createRecoverBlock(f *Function) { T := R.At(i).Type() // Return zero value of each result type. - results = append(results, zeroValue(f, T)) + results = append(results, zeroConst(T)) } } f.emit(&Return{Results: results}) diff --git a/vendor/golang.org/x/tools/go/ssa/func.go b/vendor/golang.org/x/tools/go/ssa/func.go index 57f5f718f..22f878d4e 100644 --- a/vendor/golang.org/x/tools/go/ssa/func.go +++ b/vendor/golang.org/x/tools/go/ssa/func.go @@ -10,13 +10,10 @@ import ( "bytes" "fmt" "go/ast" - "go/token" "go/types" "io" "os" "strings" - - "golang.org/x/tools/internal/typeparams" ) // Like ObjectOf, but panics instead of returning nil. @@ -46,7 +43,7 @@ func (f *Function) typ(T types.Type) types.Type { // If id is an Instance, returns info.Instances[id].Type. // Otherwise returns f.typeOf(id). func (f *Function) instanceType(id *ast.Ident) types.Type { - if t, ok := typeparams.GetInstances(f.info)[id]; ok { + if t, ok := f.info.Instances[id]; ok { return t.Type } return f.typeOf(id) @@ -108,52 +105,40 @@ type lblock struct { // labelledBlock returns the branch target associated with the // specified label, creating it if needed. func (f *Function) labelledBlock(label *ast.Ident) *lblock { - obj := f.objectOf(label) + obj := f.objectOf(label).(*types.Label) lb := f.lblocks[obj] if lb == nil { lb = &lblock{_goto: f.newBasicBlock(label.Name)} if f.lblocks == nil { - f.lblocks = make(map[types.Object]*lblock) + f.lblocks = make(map[*types.Label]*lblock) } f.lblocks[obj] = lb } return lb } -// addParam adds a (non-escaping) parameter to f.Params of the -// specified name, type and source position. -func (f *Function) addParam(name string, typ types.Type, pos token.Pos) *Parameter { - v := &Parameter{ - name: name, - typ: typ, - pos: pos, - parent: f, - } - f.Params = append(f.Params, v) - return v -} - -func (f *Function) addParamObj(obj types.Object) *Parameter { - name := obj.Name() +// addParamVar adds a parameter to f.Params. +func (f *Function) addParamVar(v *types.Var) *Parameter { + name := v.Name() if name == "" { name = fmt.Sprintf("arg%d", len(f.Params)) } - param := f.addParam(name, f.typ(obj.Type()), obj.Pos()) - param.object = obj + param := &Parameter{ + name: name, + object: v, + typ: f.typ(v.Type()), + parent: f, + } + f.Params = append(f.Params, param) return param } // addSpilledParam declares a parameter that is pre-spilled to the // stack; the function body will load/store the spilled location. // Subsequent lifting will eliminate spills where possible. -func (f *Function) addSpilledParam(obj types.Object) { - param := f.addParamObj(obj) - spill := &Alloc{Comment: obj.Name()} - spill.setType(types.NewPointer(param.Type())) - spill.setPos(obj.Pos()) - f.objects[obj] = spill - f.Locals = append(f.Locals, spill) - f.emit(spill) +func (f *Function) addSpilledParam(obj *types.Var) { + param := f.addParamVar(obj) + spill := emitLocalVar(f, obj) f.emit(&Store{Addr: spill, Val: param}) } @@ -161,7 +146,7 @@ func (f *Function) addSpilledParam(obj types.Object) { // Precondition: f.Type() already set. func (f *Function) startBody() { f.currentBlock = f.newBasicBlock("entry") - f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init + f.vars = make(map[*types.Var]Value) // needed for some synthetics, e.g. init } // createSyntacticParams populates f.Params and generates code (spills @@ -177,11 +162,11 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func if recv != nil { for _, field := range recv.List { for _, n := range field.Names { - f.addSpilledParam(f.info.Defs[n]) + f.addSpilledParam(identVar(f, n)) } // Anonymous receiver? No need to spill. if field.Names == nil { - f.addParamObj(f.Signature.Recv()) + f.addParamVar(f.Signature.Recv()) } } } @@ -191,11 +176,11 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func n := len(f.Params) // 1 if has recv, 0 otherwise for _, field := range functype.Params.List { for _, n := range field.Names { - f.addSpilledParam(f.info.Defs[n]) + f.addSpilledParam(identVar(f, n)) } // Anonymous parameter? No need to spill. if field.Names == nil { - f.addParamObj(f.Signature.Params().At(len(f.Params) - n)) + f.addParamVar(f.Signature.Params().At(len(f.Params) - n)) } } } @@ -205,7 +190,8 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func for _, field := range functype.Results.List { // Implicit "var" decl of locals for named results. for _, n := range field.Names { - f.namedResults = append(f.namedResults, f.addLocalForIdent(n)) + namedResult := emitLocalVar(f, identVar(f, n)) + f.namedResults = append(f.namedResults, namedResult) } } } @@ -250,49 +236,14 @@ func buildReferrers(f *Function) { } } -// mayNeedRuntimeTypes returns all of the types in the body of fn that might need runtime types. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func mayNeedRuntimeTypes(fn *Function) []types.Type { - // Collect all types that may need rtypes, i.e. those that flow into an interface. - var ts []types.Type - for _, bb := range fn.Blocks { - for _, instr := range bb.Instrs { - if mi, ok := instr.(*MakeInterface); ok { - ts = append(ts, mi.X.Type()) - } - } - } - - // Types that contain a parameterized type are considered to not be runtime types. - if fn.typeparams.Len() == 0 { - return ts // No potentially parameterized types. - } - // Filter parameterized types, in place. - fn.Prog.methodsMu.Lock() - defer fn.Prog.methodsMu.Unlock() - filtered := ts[:0] - for _, t := range ts { - if !fn.Prog.parameterized.isParameterized(t) { - filtered = append(filtered, t) - } - } - return filtered -} - // finishBody() finalizes the contents of the function after SSA code generation of its body. // // The function is not done being built until done() is called. func (f *Function) finishBody() { - f.objects = nil + f.vars = nil f.currentBlock = nil f.lblocks = nil - // Don't pin the AST in memory (except in debug mode). - if n := f.syntax; n != nil && !f.debugInfo() { - f.syntax = extentNode{n.Pos(), n.End()} - } - // Remove from f.Locals any Allocs that escape to the heap. j := 0 for _, l := range f.Locals { @@ -320,15 +271,15 @@ func (f *Function) finishBody() { lift(f) } - // clear remaining stateful variables + // clear remaining builder state f.namedResults = nil // (used by lifting) - f.info = nil f.subst = nil numberRegisters(f) // uses f.namedRegisters } -// After this, function is done with BUILD phase. +// done marks the building of f's SSA body complete, +// along with any nested functions, and optionally prints them. func (f *Function) done() { assert(f.parent == nil, "done called on an anonymous function") @@ -338,7 +289,7 @@ func (f *Function) done() { visit(anon) // anon is done building before f. } - f.built = true // function is done with BUILD phase + f.build = nil // function is built if f.Prog.mode&PrintFunctions != 0 { printMu.Lock() @@ -376,49 +327,35 @@ func (f *Function) removeNilBlocks() { // size of the instruction stream, and causes Functions to depend upon // the ASTs, potentially keeping them live in memory for longer. func (pkg *Package) SetDebugMode(debug bool) { - // TODO(adonovan): do we want ast.File granularity? pkg.debug = debug } // debugInfo reports whether debug info is wanted for this function. func (f *Function) debugInfo() bool { - return f.Pkg != nil && f.Pkg.debug -} - -// addNamedLocal creates a local variable, adds it to function f and -// returns it. Its name and type are taken from obj. Subsequent -// calls to f.lookup(obj) will return the same local. -func (f *Function) addNamedLocal(obj types.Object) *Alloc { - l := f.addLocal(obj.Type(), obj.Pos()) - l.Comment = obj.Name() - f.objects[obj] = l - return l -} - -func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc { - return f.addNamedLocal(f.info.Defs[id]) -} - -// addLocal creates an anonymous local variable of type typ, adds it -// to function f and returns it. pos is the optional source location. -func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc { - typ = f.typ(typ) - v := &Alloc{} - v.setType(types.NewPointer(typ)) - v.setPos(pos) - f.Locals = append(f.Locals, v) - f.emit(v) - return v + // debug info for instantiations follows the debug info of their origin. + p := f.declaredPackage() + return p != nil && p.debug } // lookup returns the address of the named variable identified by obj // that is local to function f or one of its enclosing functions. // If escaping, the reference comes from a potentially escaping pointer // expression and the referent must be heap-allocated. -func (f *Function) lookup(obj types.Object, escaping bool) Value { - if v, ok := f.objects[obj]; ok { - if alloc, ok := v.(*Alloc); ok && escaping { - alloc.Heap = true +// We assume the referent is a *Alloc or *Phi. +// (The only Phis at this stage are those created directly by go1.22 "for" loops.) +func (f *Function) lookup(obj *types.Var, escaping bool) Value { + if v, ok := f.vars[obj]; ok { + if escaping { + switch v := v.(type) { + case *Alloc: + v.Heap = true + case *Phi: + for _, edge := range v.Edges { + if alloc, ok := edge.(*Alloc); ok { + alloc.Heap = true + } + } + } } return v // function-local var (address) } @@ -436,7 +373,7 @@ func (f *Function) lookup(obj types.Object, escaping bool) Value { outer: outer, parent: f, } - f.objects[obj] = v + f.vars[obj] = v f.FreeVars = append(f.FreeVars, v) return v } @@ -514,15 +451,15 @@ func (f *Function) relMethod(from *types.Package, recv types.Type) string { } // writeSignature writes to buf the signature sig in declaration syntax. -func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature, params []*Parameter) { +func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature) { buf.WriteString("func ") if recv := sig.Recv(); recv != nil { buf.WriteString("(") - if n := params[0].Name(); n != "" { - buf.WriteString(n) + if name := recv.Name(); name != "" { + buf.WriteString(name) buf.WriteString(" ") } - types.WriteType(buf, params[0].Type(), types.RelativeTo(from)) + types.WriteType(buf, recv.Type(), types.RelativeTo(from)) buf.WriteString(") ") } buf.WriteString(name) @@ -534,7 +471,7 @@ func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *ty func (fn *Function) declaredPackage() *Package { switch { case fn.Pkg != nil: - return fn.Pkg // non-generic function + return fn.Pkg // non-generic function (does that follow??) case fn.topLevelOrigin != nil: return fn.topLevelOrigin.Pkg // instance of a named generic function case fn.parent != nil: @@ -594,10 +531,10 @@ func WriteFunction(buf *bytes.Buffer, f *Function) { if len(f.Locals) > 0 { buf.WriteString("# Locals:\n") for i, l := range f.Locals { - fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), from)) + fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(mustDeref(l.Type()), from)) } } - writeSignature(buf, from, f.Name(), f.Signature, f.Params) + writeSignature(buf, from, f.Name(), f.Signature) buf.WriteString(":\n") if f.Blocks == nil { @@ -687,17 +624,11 @@ func (prog *Program) NewFunction(name string, sig *types.Signature, provenance s return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance} } -type extentNode [2]token.Pos - -func (n extentNode) Pos() token.Pos { return n[0] } -func (n extentNode) End() token.Pos { return n[1] } - -// Syntax returns an ast.Node whose Pos/End methods provide the -// lexical extent of the function if it was defined by Go source code -// (f.Synthetic==""), or nil otherwise. -// -// If f was built with debug information (see Package.SetDebugRef), -// the result is the *ast.FuncDecl or *ast.FuncLit that declared the -// function. Otherwise, it is an opaque Node providing only position -// information; this avoids pinning the AST in memory. +// Syntax returns the function's syntax (*ast.Func{Decl,Lit) +// if it was produced from syntax. func (f *Function) Syntax() ast.Node { return f.syntax } + +// identVar returns the variable defined by id. +func identVar(fn *Function, id *ast.Ident) *types.Var { + return fn.info.Defs[id].(*types.Var) +} diff --git a/vendor/golang.org/x/tools/go/ssa/identical.go b/vendor/golang.org/x/tools/go/ssa/identical.go deleted file mode 100644 index e8026967b..000000000 --- a/vendor/golang.org/x/tools/go/ssa/identical.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.8 -// +build go1.8 - -package ssa - -import "go/types" - -var structTypesIdentical = types.IdenticalIgnoreTags diff --git a/vendor/golang.org/x/tools/go/ssa/identical_17.go b/vendor/golang.org/x/tools/go/ssa/identical_17.go deleted file mode 100644 index 575aa5dfc..000000000 --- a/vendor/golang.org/x/tools/go/ssa/identical_17.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.8 -// +build !go1.8 - -package ssa - -import "go/types" - -var structTypesIdentical = types.Identical diff --git a/vendor/golang.org/x/tools/go/ssa/instantiate.go b/vendor/golang.org/x/tools/go/ssa/instantiate.go index 38249dea2..c155f6736 100644 --- a/vendor/golang.org/x/tools/go/ssa/instantiate.go +++ b/vendor/golang.org/x/tools/go/ssa/instantiate.go @@ -6,130 +6,60 @@ package ssa import ( "fmt" - "go/ast" "go/types" + "sync" "golang.org/x/tools/internal/typeparams" ) -// _Instances returns all of the instances generated by runtime types for this function in an unspecified order. -// -// Thread-safe. -// -// This is an experimental interface! It may change without warning. -func (prog *Program) _Instances(fn *Function) []*Function { - if fn.typeparams.Len() == 0 || len(fn.typeargs) > 0 { - return nil - } - - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - return prog.instances[fn].list() -} - -// A set of instantiations of a generic function fn. -type instanceSet struct { - fn *Function // fn.typeparams.Len() > 0 and len(fn.typeargs) == 0. - instances map[*typeList]*Function // canonical type arguments to an instance. - syntax *ast.FuncDecl // fn.syntax copy for instantiating after fn is done. nil on synthetic packages. - info *types.Info // fn.pkg.info copy for building after fn is done.. nil on synthetic packages. - - // TODO(taking): Consider ways to allow for clearing syntax and info when done building. - // May require a public API change as MethodValue can request these be built after prog.Build() is done. -} - -func (insts *instanceSet) list() []*Function { - if insts == nil { - return nil - } - - fns := make([]*Function, 0, len(insts.instances)) - for _, fn := range insts.instances { - fns = append(fns, fn) - } - return fns +// A generic records information about a generic origin function, +// including a cache of existing instantiations. +type generic struct { + instancesMu sync.Mutex + instances map[*typeList]*Function // canonical type arguments to an instance. } -// createInstanceSet adds a new instanceSet for a generic function fn if one does not exist. +// instance returns a Function that is the instantiation of generic +// origin function fn with the type arguments targs. // -// Precondition: fn is a package level declaration (function or method). +// Any created instance is added to cr. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) -func (prog *Program) createInstanceSet(fn *Function) { - assert(fn.typeparams.Len() > 0 && len(fn.typeargs) == 0, "Can only create instance sets for generic functions") - - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - syntax, _ := fn.syntax.(*ast.FuncDecl) - assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl") - - if _, ok := prog.instances[fn]; !ok { - prog.instances[fn] = &instanceSet{ - fn: fn, - syntax: syntax, - info: fn.info, +// Acquires fn.generic.instancesMu. +func (fn *Function) instance(targs []types.Type, cr *creator) *Function { + key := fn.Prog.canon.List(targs) + + gen := fn.generic + + gen.instancesMu.Lock() + defer gen.instancesMu.Unlock() + inst, ok := gen.instances[key] + if !ok { + inst = createInstance(fn, targs, cr) + if gen.instances == nil { + gen.instances = make(map[*typeList]*Function) } + gen.instances[key] = inst } + return inst } -// needsInstance returns a Function that is the instantiation of fn with the type arguments targs. -// -// Any CREATEd instance is added to cr. -// -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) -func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function { - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - return prog.lookupOrCreateInstance(fn, targs, cr) -} - -// lookupOrCreateInstance returns a Function that is the instantiation of fn with the type arguments targs. -// -// Any CREATEd instance is added to cr. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodMu) -func (prog *Program) lookupOrCreateInstance(fn *Function, targs []types.Type, cr *creator) *Function { - return prog.instances[fn].lookupOrCreate(targs, &prog.parameterized, cr) -} - -// lookupOrCreate returns the instantiation of insts.fn using targs. +// createInstance returns the instantiation of generic function fn using targs. // If the instantiation is created, this is added to cr. -func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWalker, cr *creator) *Function { - if insts.instances == nil { - insts.instances = make(map[*typeList]*Function) - } - - fn := insts.fn +// +// Requires fn.generic.instancesMu. +func createInstance(fn *Function, targs []types.Type, cr *creator) *Function { prog := fn.Prog - // canonicalize on a tuple of targs. Sig is not unique. - // - // func A[T any]() { - // var x T - // fmt.Println("%T", x) - // } - key := prog.canon.List(targs) - if inst, ok := insts.instances[key]; ok { - return inst - } - - // CREATE instance/instantiation wrapper - var syntax ast.Node - if insts.syntax != nil { - syntax = insts.syntax - } - + // Compute signature. var sig *types.Signature var obj *types.Func if recv := fn.Signature.Recv(); recv != nil { // method - m := fn.object.(*types.Func) - obj = prog.canon.instantiateMethod(m, targs, prog.ctxt) + obj = prog.canon.instantiateMethod(fn.object, targs, prog.ctxt) sig = obj.Type().(*types.Signature) } else { - instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false) + // function + instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false) if err != nil { panic(err) } @@ -137,41 +67,48 @@ func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWa if !ok { panic("Instantiate of a Signature returned a non-signature") } - obj = fn.object.(*types.Func) // instantiation does not exist yet + obj = fn.object // instantiation does not exist yet sig = prog.canon.Type(instance).(*types.Signature) } - var synthetic string - var subst *subster - - concrete := !parameterized.anyParameterized(targs) - - if prog.mode&InstantiateGenerics != 0 && concrete { + // Choose strategy (instance or wrapper). + var ( + synthetic string + subst *subster + build buildFunc + ) + if prog.mode&InstantiateGenerics != 0 && !prog.parameterized.anyParameterized(targs) { synthetic = fmt.Sprintf("instance of %s", fn.Name()) - scope := typeparams.OriginMethod(obj).Scope() - subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false) + if fn.syntax != nil { + scope := typeparams.OriginMethod(obj).Scope() + subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false) + build = (*builder).buildFromSyntax + } else { + build = (*builder).buildParamsOnly + } } else { synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name()) + build = (*builder).buildInstantiationWrapper } - name := fmt.Sprintf("%s%s", fn.Name(), targs) // may not be unique + /* generic instance or instantiation wrapper */ instance := &Function{ - name: name, + name: fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique object: obj, Signature: sig, Synthetic: synthetic, - syntax: syntax, + syntax: fn.syntax, // \ + info: fn.info, // } empty for non-created packages + goversion: fn.goversion, // / + build: build, topLevelOrigin: fn, pos: obj.Pos(), Pkg: nil, Prog: fn.Prog, typeparams: fn.typeparams, // share with origin typeargs: targs, - info: insts.info, // on synthetic packages info is nil. subst: subst, } - cr.Add(instance) - insts.instances[key] = instance return instance } diff --git a/vendor/golang.org/x/tools/go/ssa/lift.go b/vendor/golang.org/x/tools/go/ssa/lift.go index 945536bbb..da49fe9f1 100644 --- a/vendor/golang.org/x/tools/go/ssa/lift.go +++ b/vendor/golang.org/x/tools/go/ssa/lift.go @@ -41,11 +41,8 @@ package ssa import ( "fmt" "go/token" - "go/types" "math/big" "os" - - "golang.org/x/tools/internal/typeparams" ) // If true, show diagnostic information at each step of lifting. @@ -106,9 +103,14 @@ func buildDomFrontier(fn *Function) domFrontier { } func removeInstr(refs []Instruction, instr Instruction) []Instruction { + return removeInstrsIf(refs, func(i Instruction) bool { return i == instr }) +} + +func removeInstrsIf(refs []Instruction, p func(Instruction) bool) []Instruction { + // TODO(taking): replace with go1.22 slices.DeleteFunc. i := 0 for _, ref := range refs { - if ref == instr { + if p(ref) { continue } refs[i] = ref @@ -383,12 +385,6 @@ type newPhiMap map[*BasicBlock][]newPhi // // fresh is a source of fresh ids for phi nodes. func liftAlloc(df domFrontier, alloc *Alloc, newPhis newPhiMap, fresh *int) bool { - // TODO(taking): zero constants of aggregated types can now be lifted. - switch deref(alloc.Type()).Underlying().(type) { - case *types.Array, *types.Struct, *typeparams.TypeParam: - return false - } - // Don't lift named return values in functions that defer // calls that may recover from panic. if fn := alloc.Parent(); fn.Recover != nil { @@ -469,7 +465,7 @@ func liftAlloc(df domFrontier, alloc *Alloc, newPhis newPhiMap, fresh *int) bool *fresh++ phi.pos = alloc.Pos() - phi.setType(deref(alloc.Type())) + phi.setType(mustDeref(alloc.Type())) phi.block = v if debugLifting { fmt.Fprintf(os.Stderr, "\tplace %s = %s at block %s\n", phi.Name(), phi, v) @@ -514,7 +510,7 @@ func replaceAll(x, y Value) { func renamed(renaming []Value, alloc *Alloc) Value { v := renaming[alloc.index] if v == nil { - v = zeroConst(deref(alloc.Type())) + v = zeroConst(mustDeref(alloc.Type())) renaming[alloc.index] = v } return v diff --git a/vendor/golang.org/x/tools/go/ssa/lvalue.go b/vendor/golang.org/x/tools/go/ssa/lvalue.go index 51122b8e8..186cfcae7 100644 --- a/vendor/golang.org/x/tools/go/ssa/lvalue.go +++ b/vendor/golang.org/x/tools/go/ssa/lvalue.go @@ -25,7 +25,7 @@ type lvalue interface { // An address is an lvalue represented by a true pointer. type address struct { - addr Value + addr Value // must have a pointer core type. pos token.Pos // source position expr ast.Expr // source syntax of the value (not address) [debug mode] } @@ -52,7 +52,7 @@ func (a *address) address(fn *Function) Value { } func (a *address) typ() types.Type { - return deref(a.addr.Type()) + return mustDeref(a.addr.Type()) } // An element is an lvalue represented by m[k], the location of an diff --git a/vendor/golang.org/x/tools/go/ssa/methods.go b/vendor/golang.org/x/tools/go/ssa/methods.go index 4185618cd..4797b3928 100644 --- a/vendor/golang.org/x/tools/go/ssa/methods.go +++ b/vendor/golang.org/x/tools/go/ssa/methods.go @@ -10,54 +10,124 @@ import ( "fmt" "go/types" + "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/typeparams" ) // MethodValue returns the Function implementing method sel, building -// wrapper methods on demand. It returns nil if sel denotes an -// abstract (interface or parameterized) method. +// wrapper methods on demand. It returns nil if sel denotes an +// interface or generic method. // // Precondition: sel.Kind() == MethodVal. // // Thread-safe. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) +// Acquires prog.methodsMu. func (prog *Program) MethodValue(sel *types.Selection) *Function { if sel.Kind() != types.MethodVal { panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel)) } T := sel.Recv() if types.IsInterface(T) { - return nil // abstract method (interface, possibly type param) + return nil // interface method or type parameter } + + if prog.parameterized.isParameterized(T) { + return nil // generic method + } + if prog.mode&LogSource != 0 { defer logStack("MethodValue %s %v", T, sel)() } - var m *Function - b := builder{created: &creator{}} + var cr creator - prog.methodsMu.Lock() - // Checks whether a type param is reachable from T. - // This is an expensive check. May need to be optimized later. - if !prog.parameterized.isParameterized(T) { - m = prog.addMethod(prog.createMethodSet(T), sel, b.created) + m := func() *Function { + prog.methodsMu.Lock() + defer prog.methodsMu.Unlock() + + // Get or create SSA method set. + mset, ok := prog.methodSets.At(T).(*methodSet) + if !ok { + mset = &methodSet{mapping: make(map[string]*Function)} + prog.methodSets.Set(T, mset) + } + + // Get or create SSA method. + id := sel.Obj().Id() + fn, ok := mset.mapping[id] + if !ok { + obj := sel.Obj().(*types.Func) + _, ptrObj := deptr(recvType(obj)) + _, ptrRecv := deptr(T) + needsPromotion := len(sel.Index()) > 1 + needsIndirection := !ptrObj && ptrRecv + if needsPromotion || needsIndirection { + fn = createWrapper(prog, toSelection(sel), &cr) + } else { + fn = prog.objectMethod(obj, &cr) + } + if fn.Signature.Recv() == nil { + panic(fn) + } + mset.mapping[id] = fn + } + + return fn + }() + + b := builder{created: &cr} + b.iterate() + + return m +} + +// objectMethod returns the Function for a given method symbol. +// The symbol may be an instance of a generic function. It need not +// belong to an existing SSA package created by a call to +// prog.CreatePackage. +// +// objectMethod panics if the function is not a method. +// +// Acquires prog.objectMethodsMu. +func (prog *Program) objectMethod(obj *types.Func, cr *creator) *Function { + sig := obj.Type().(*types.Signature) + if sig.Recv() == nil { + panic("not a method: " + obj.String()) } - prog.methodsMu.Unlock() - if m == nil { - return nil // abstract method (generic) + // Belongs to a created package? + if fn := prog.FuncValue(obj); fn != nil { + return fn } - for !b.done() { - b.buildCreated() - b.needsRuntimeTypes() + + // Instantiation of generic? + if originObj := typeparams.OriginMethod(obj); originObj != obj { + origin := prog.objectMethod(originObj, cr) + assert(origin.typeparams.Len() > 0, "origin is not generic") + targs := receiverTypeArgs(obj) + return origin.instance(targs, cr) } - return m + + // Consult/update cache of methods created from types.Func. + prog.objectMethodsMu.Lock() + defer prog.objectMethodsMu.Unlock() + fn, ok := prog.objectMethods[obj] + if !ok { + fn = createFunction(prog, obj, obj.Name(), nil, nil, "", cr) + fn.Synthetic = "from type information (on demand)" + + if prog.objectMethods == nil { + prog.objectMethods = make(map[*types.Func]*Function) + } + prog.objectMethods[obj] = fn + } + return fn } // LookupMethod returns the implementation of the method of type T // identified by (pkg, name). It returns nil if the method exists but -// is abstract, and panics if T has no such method. +// is an interface method or generic method, and panics if T has no such method. func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function { sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name) if sel == nil { @@ -68,205 +138,136 @@ func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) // methodSet contains the (concrete) methods of a concrete type (non-interface, non-parameterized). type methodSet struct { - mapping map[string]*Function // populated lazily - complete bool // mapping contains all methods -} - -// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized. -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) createMethodSet(T types.Type) *methodSet { - if prog.mode&SanityCheckFunctions != 0 { - if types.IsInterface(T) || prog.parameterized.isParameterized(T) { - panic("type is interface or parameterized") - } - } - mset, ok := prog.methodSets.At(T).(*methodSet) - if !ok { - mset = &methodSet{mapping: make(map[string]*Function)} - prog.methodSets.Set(T, mset) - } - return mset -} - -// Adds any created functions to cr. -// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized. -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creator) *Function { - if sel.Kind() == types.MethodExpr { - panic(sel) - } - id := sel.Obj().Id() - fn := mset.mapping[id] - if fn == nil { - sel := toSelection(sel) - obj := sel.obj.(*types.Func) - - needsPromotion := len(sel.index) > 1 - needsIndirection := !isPointer(recvType(obj)) && isPointer(sel.recv) - if needsPromotion || needsIndirection { - fn = makeWrapper(prog, sel, cr) - } else { - fn = prog.originFunc(obj) - if fn.typeparams.Len() > 0 { // instantiate - targs := receiverTypeArgs(obj) - fn = prog.lookupOrCreateInstance(fn, targs, cr) - } - } - if fn.Signature.Recv() == nil { - panic(fn) // missing receiver - } - mset.mapping[id] = fn - } - return fn + mapping map[string]*Function // populated lazily } -// RuntimeTypes returns a new unordered slice containing all -// concrete types in the program for which a complete (non-empty) -// method set is required at run-time. +// RuntimeTypes returns a new unordered slice containing all types in +// the program for which a runtime type is required. +// +// A runtime type is required for any non-parameterized, non-interface +// type that is converted to an interface, or for any type (including +// interface types) derivable from one through reflection. +// +// The methods of such types may be reachable through reflection or +// interface calls even if they are never called directly. // // Thread-safe. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) +// Acquires prog.runtimeTypesMu. func (prog *Program) RuntimeTypes() []types.Type { - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - var res []types.Type - prog.methodSets.Iterate(func(T types.Type, v interface{}) { - if v.(*methodSet).complete { - res = append(res, T) - } - }) - return res -} - -// declaredFunc returns the concrete function/method denoted by obj. -// Panic ensues if there is none. -func (prog *Program) declaredFunc(obj *types.Func) *Function { - if v := prog.packageLevelMember(obj); v != nil { - return v.(*Function) - } - panic("no concrete method: " + obj.String()) + prog.runtimeTypesMu.Lock() + defer prog.runtimeTypesMu.Unlock() + return prog.runtimeTypes.Keys() } -// needMethodsOf ensures that runtime type information (including the -// complete method set) is available for the specified type T and all -// its subcomponents. -// -// needMethodsOf must be called for at least every type that is an -// operand of some MakeInterface instruction, and for the type of -// every exported package member. -// -// Adds any created functions to cr. -// -// Precondition: T is not a method signature (*Signature with Recv()!=nil). -// Precondition: T is not parameterized. -// -// Thread-safe. (Called via Package.build from multiple builder goroutines.) +// forEachReachable calls f for type T and each type reachable from +// its type through reflection. // -// TODO(adonovan): make this faster. It accounts for 20% of SSA build time. +// The function f must use memoization to break cycles and +// return false when the type has already been visited. // -// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu) -func (prog *Program) needMethodsOf(T types.Type, cr *creator) { - prog.methodsMu.Lock() - prog.needMethods(T, false, cr) - prog.methodsMu.Unlock() -} - -// Precondition: T is not a method signature (*Signature with Recv()!=nil). -// Precondition: T is not parameterized. -// Recursive case: skip => don't create methods for T. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func (prog *Program) needMethods(T types.Type, skip bool, cr *creator) { - // Each package maintains its own set of types it has visited. - if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok { - // needMethods(T) was previously called - if !prevSkip || skip { - return // already seen, with same or false 'skip' value - } - } - prog.runtimeTypes.Set(T, skip) - - tmset := prog.MethodSets.MethodSet(T) - - if !skip && !types.IsInterface(T) && tmset.Len() > 0 { - // Create methods of T. - mset := prog.createMethodSet(T) - if !mset.complete { - mset.complete = true - n := tmset.Len() - for i := 0; i < n; i++ { - prog.addMethod(mset, tmset.At(i), cr) +// TODO(adonovan): publish in typeutil and share with go/callgraph/rta. +func forEachReachable(msets *typeutil.MethodSetCache, T types.Type, f func(types.Type) bool) { + var visit func(T types.Type, skip bool) + visit = func(T types.Type, skip bool) { + if !skip { + if !f(T) { + return } } - } - - // Recursion over signatures of each method. - for i := 0; i < tmset.Len(); i++ { - sig := tmset.At(i).Type().(*types.Signature) - prog.needMethods(sig.Params(), false, cr) - prog.needMethods(sig.Results(), false, cr) - } - switch t := T.(type) { - case *types.Basic: - // nop + // Recursion over signatures of each method. + tmset := msets.MethodSet(T) + for i := 0; i < tmset.Len(); i++ { + sig := tmset.At(i).Type().(*types.Signature) + // It is tempting to call visit(sig, false) + // but, as noted in golang.org/cl/65450043, + // the Signature.Recv field is ignored by + // types.Identical and typeutil.Map, which + // is confusing at best. + // + // More importantly, the true signature rtype + // reachable from a method using reflection + // has no receiver but an extra ordinary parameter. + // For the Read method of io.Reader we want: + // func(Reader, []byte) (int, error) + // but here sig is: + // func([]byte) (int, error) + // with .Recv = Reader (though it is hard to + // notice because it doesn't affect Signature.String + // or types.Identical). + // + // TODO(adonovan): construct and visit the correct + // non-method signature with an extra parameter + // (though since unnamed func types have no methods + // there is essentially no actual demand for this). + // + // TODO(adonovan): document whether or not it is + // safe to skip non-exported methods (as RTA does). + visit(sig.Params(), true) // skip the Tuple + visit(sig.Results(), true) // skip the Tuple + } - case *types.Interface: - // nop---handled by recursion over method set. + switch T := T.(type) { + case *types.Basic: + // nop - case *types.Pointer: - prog.needMethods(t.Elem(), false, cr) + case *types.Interface: + // nop---handled by recursion over method set. - case *types.Slice: - prog.needMethods(t.Elem(), false, cr) + case *types.Pointer: + visit(T.Elem(), false) - case *types.Chan: - prog.needMethods(t.Elem(), false, cr) + case *types.Slice: + visit(T.Elem(), false) - case *types.Map: - prog.needMethods(t.Key(), false, cr) - prog.needMethods(t.Elem(), false, cr) + case *types.Chan: + visit(T.Elem(), false) - case *types.Signature: - if t.Recv() != nil { - panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv())) - } - prog.needMethods(t.Params(), false, cr) - prog.needMethods(t.Results(), false, cr) - - case *types.Named: - // A pointer-to-named type can be derived from a named - // type via reflection. It may have methods too. - prog.needMethods(types.NewPointer(T), false, cr) - - // Consider 'type T struct{S}' where S has methods. - // Reflection provides no way to get from T to struct{S}, - // only to S, so the method set of struct{S} is unwanted, - // so set 'skip' flag during recursion. - prog.needMethods(t.Underlying(), true, cr) - - case *types.Array: - prog.needMethods(t.Elem(), false, cr) - - case *types.Struct: - for i, n := 0, t.NumFields(); i < n; i++ { - prog.needMethods(t.Field(i).Type(), false, cr) - } + case *types.Map: + visit(T.Key(), false) + visit(T.Elem(), false) - case *types.Tuple: - for i, n := 0, t.Len(); i < n; i++ { - prog.needMethods(t.At(i).Type(), false, cr) - } + case *types.Signature: + if T.Recv() != nil { + panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv())) + } + visit(T.Params(), true) // skip the Tuple + visit(T.Results(), true) // skip the Tuple + + case *types.Named: + // A pointer-to-named type can be derived from a named + // type via reflection. It may have methods too. + visit(types.NewPointer(T), false) + + // Consider 'type T struct{S}' where S has methods. + // Reflection provides no way to get from T to struct{S}, + // only to S, so the method set of struct{S} is unwanted, + // so set 'skip' flag during recursion. + visit(T.Underlying(), true) // skip the unnamed type + + case *types.Array: + visit(T.Elem(), false) + + case *types.Struct: + for i, n := 0, T.NumFields(); i < n; i++ { + // TODO(adonovan): document whether or not + // it is safe to skip non-exported fields. + visit(T.Field(i).Type(), false) + } - case *typeparams.TypeParam: - panic(T) // type parameters are always abstract. + case *types.Tuple: + for i, n := 0, T.Len(); i < n; i++ { + visit(T.At(i).Type(), false) + } - case *typeparams.Union: - // nop + case *types.TypeParam, *types.Union: + // forEachReachable must not be called on parameterized types. + panic(T) - default: - panic(T) + default: + panic(T) + } } + visit(T, false) } diff --git a/vendor/golang.org/x/tools/go/ssa/parameterized.go b/vendor/golang.org/x/tools/go/ssa/parameterized.go index 3fc4348fc..84db49d39 100644 --- a/vendor/golang.org/x/tools/go/ssa/parameterized.go +++ b/vendor/golang.org/x/tools/go/ssa/parameterized.go @@ -6,6 +6,7 @@ package ssa import ( "go/types" + "sync" "golang.org/x/tools/internal/typeparams" ) @@ -14,11 +15,24 @@ import ( // // NOTE: Adapted from go/types/infer.go. If that is exported in a future release remove this copy. type tpWalker struct { + mu sync.Mutex seen map[types.Type]bool } -// isParameterized returns true when typ reaches any type parameter. -func (w *tpWalker) isParameterized(typ types.Type) (res bool) { +// isParameterized reports whether t recursively contains a type parameter. +// Thread-safe. +func (w *tpWalker) isParameterized(t types.Type) bool { + // TODO(adonovan): profile. If this operation is expensive, + // handle the most common but shallow cases such as T, pkg.T, + // *T without consulting the cache under the lock. + + w.mu.Lock() + defer w.mu.Unlock() + return w.isParameterizedLocked(t) +} + +// Requires w.mu. +func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) { // NOTE: Adapted from go/types/infer.go. Try to keep in sync. // detect cycles @@ -35,25 +49,25 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { break case *types.Array: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Slice: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Struct: for i, n := 0, t.NumFields(); i < n; i++ { - if w.isParameterized(t.Field(i).Type()) { + if w.isParameterizedLocked(t.Field(i).Type()) { return true } } case *types.Pointer: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Tuple: n := t.Len() for i := 0; i < n; i++ { - if w.isParameterized(t.At(i).Type()) { + if w.isParameterizedLocked(t.At(i).Type()) { return true } } @@ -63,14 +77,14 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { // of a generic function type (or an interface method) that is // part of the type we're testing. We don't care about these type // parameters. - // Similarly, the receiver of a method may declare (rather then + // Similarly, the receiver of a method may declare (rather than // use) type parameters, we don't care about those either. // Thus, we only need to look at the input and result parameters. - return w.isParameterized(t.Params()) || w.isParameterized(t.Results()) + return w.isParameterizedLocked(t.Params()) || w.isParameterizedLocked(t.Results()) case *types.Interface: for i, n := 0, t.NumMethods(); i < n; i++ { - if w.isParameterized(t.Method(i).Type()) { + if w.isParameterizedLocked(t.Method(i).Type()) { return true } } @@ -79,31 +93,31 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { panic(err) } for _, term := range terms { - if w.isParameterized(term.Type()) { + if w.isParameterizedLocked(term.Type()) { return true } } case *types.Map: - return w.isParameterized(t.Key()) || w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Key()) || w.isParameterizedLocked(t.Elem()) case *types.Chan: - return w.isParameterized(t.Elem()) + return w.isParameterizedLocked(t.Elem()) case *types.Named: - args := typeparams.NamedTypeArgs(t) + args := t.TypeArgs() // TODO(taking): this does not match go/types/infer.go. Check with rfindley. - if params := typeparams.ForNamed(t); params.Len() > args.Len() { + if params := t.TypeParams(); params.Len() > args.Len() { return true } for i, n := 0, args.Len(); i < n; i++ { - if w.isParameterized(args.At(i)) { + if w.isParameterizedLocked(args.At(i)) { return true } } - return w.isParameterized(t.Underlying()) // recurse for types local to parameterized functions + return w.isParameterizedLocked(t.Underlying()) // recurse for types local to parameterized functions - case *typeparams.TypeParam: + case *types.TypeParam: return true default: @@ -113,9 +127,13 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) { return false } +// anyParameterized reports whether any element of ts is parameterized. +// Thread-safe. func (w *tpWalker) anyParameterized(ts []types.Type) bool { + w.mu.Lock() + defer w.mu.Unlock() for _, t := range ts { - if w.isParameterized(t) { + if w.isParameterizedLocked(t) { return true } } diff --git a/vendor/golang.org/x/tools/go/ssa/print.go b/vendor/golang.org/x/tools/go/ssa/print.go index 8b783196e..727a73502 100644 --- a/vendor/golang.org/x/tools/go/ssa/print.go +++ b/vendor/golang.org/x/tools/go/ssa/print.go @@ -17,7 +17,6 @@ import ( "strings" "golang.org/x/tools/go/types/typeutil" - "golang.org/x/tools/internal/typeparams" ) // relName returns the name of v relative to i. @@ -51,7 +50,7 @@ func relType(t types.Type, from *types.Package) string { return s } -func relTerm(term *typeparams.Term, from *types.Package) string { +func relTerm(term *types.Term, from *types.Package) string { s := relType(term.Type(), from) if term.Tilde() { return "~" + s @@ -95,7 +94,7 @@ func (v *Alloc) String() string { op = "new" } from := v.Parent().relPkg() - return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), from), v.Comment) + return fmt.Sprintf("%s %s (%s)", op, relType(mustDeref(v.Type()), from), v.Comment) } func (v *Phi) String() string { @@ -259,21 +258,19 @@ func (v *MakeChan) String() string { } func (v *FieldAddr) String() string { - st := typeparams.CoreType(deref(v.X.Type())).(*types.Struct) // Be robust against a bad index. name := "?" - if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name() + if fld := fieldOf(mustDeref(v.X.Type()), v.Field); fld != nil { + name = fld.Name() } return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) } func (v *Field) String() string { - st := typeparams.CoreType(v.X.Type()).(*types.Struct) // Be robust against a bad index. name := "?" - if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name() + if fld := fieldOf(v.X.Type(), v.Field); fld != nil { + name = fld.Name() } return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field) } @@ -452,7 +449,7 @@ func WritePackage(buf *bytes.Buffer, p *Package) { case *Global: fmt.Fprintf(buf, " var %-*s %s\n", - maxname, name, relType(mem.Type().(*types.Pointer).Elem(), from)) + maxname, name, relType(mustDeref(mem.Type()), from)) } } diff --git a/vendor/golang.org/x/tools/go/ssa/sanity.go b/vendor/golang.org/x/tools/go/ssa/sanity.go index 88ad374de..22a3c6bc3 100644 --- a/vendor/golang.org/x/tools/go/ssa/sanity.go +++ b/vendor/golang.org/x/tools/go/ssa/sanity.go @@ -8,6 +8,7 @@ package ssa // Currently it checks CFG invariants but little at the instruction level. import ( + "bytes" "fmt" "go/types" "io" @@ -131,6 +132,11 @@ func (s *sanity) checkInstr(idx int, instr Instruction) { case *BinOp: case *Call: + if common := instr.Call; common.IsInvoke() { + if !types.IsInterface(common.Value.Type()) { + s.errorf("invoke on %s (%s) which is not an interface type (or type param)", common.Value, common.Value.Type()) + } + } case *ChangeInterface: case *ChangeType: case *SliceToArrayPointer: @@ -412,14 +418,17 @@ func (s *sanity) checkFunction(fn *Function) bool { s.errorf("nil Prog") } + var buf bytes.Buffer _ = fn.String() // must not crash _ = fn.RelString(fn.relPkg()) // must not crash + WriteFunction(&buf, fn) // must not crash // All functions have a package, except delegates (which are // shared across packages, or duplicated as weak symbols in a // separate-compilation model), and error.Error. if fn.Pkg == nil { - if strings.HasPrefix(fn.Synthetic, "wrapper ") || + if strings.HasPrefix(fn.Synthetic, "from type information (on demand)") || + strings.HasPrefix(fn.Synthetic, "wrapper ") || strings.HasPrefix(fn.Synthetic, "bound ") || strings.HasPrefix(fn.Synthetic, "thunk ") || strings.HasSuffix(fn.name, "Error") || diff --git a/vendor/golang.org/x/tools/go/ssa/source.go b/vendor/golang.org/x/tools/go/ssa/source.go index b9a08363e..6700305bd 100644 --- a/vendor/golang.org/x/tools/go/ssa/source.go +++ b/vendor/golang.org/x/tools/go/ssa/source.go @@ -121,7 +121,9 @@ func findNamedFunc(pkg *Package, pos token.Pos) *Function { // Don't call Program.Method: avoid creating wrappers. obj := mset.At(i).Obj().(*types.Func) if obj.Pos() == pos { - return pkg.objects[obj].(*Function) + // obj from MethodSet may not be the origin type. + m := typeparams.OriginMethod(obj) + return pkg.objects[m].(*Function) } } } @@ -170,16 +172,19 @@ func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) { // --- Lookup functions for source-level named entities (types.Objects) --- // Package returns the SSA Package corresponding to the specified -// type-checker package object. -// It returns nil if no such SSA package has been created. -func (prog *Program) Package(obj *types.Package) *Package { - return prog.packages[obj] +// type-checker package. It returns nil if no such Package was +// created by a prior call to prog.CreatePackage. +func (prog *Program) Package(pkg *types.Package) *Package { + return prog.packages[pkg] } -// packageLevelMember returns the package-level member corresponding to -// the specified named object, which may be a package-level const -// (*NamedConst), var (*Global) or func (*Function) of some package in -// prog. It returns nil if the object is not found. +// packageLevelMember returns the package-level member corresponding +// to the specified symbol, which may be a package-level const +// (*NamedConst), var (*Global) or func/method (*Function) of some +// package in prog. +// +// It returns nil if the object belongs to a package that has not been +// created by prog.CreatePackage. func (prog *Program) packageLevelMember(obj types.Object) Member { if pkg, ok := prog.packages[obj.Pkg()]; ok { return pkg.objects[obj] @@ -187,24 +192,16 @@ func (prog *Program) packageLevelMember(obj types.Object) Member { return nil } -// originFunc returns the package-level generic function that is the -// origin of obj. If returns nil if the generic function is not found. -func (prog *Program) originFunc(obj *types.Func) *Function { - return prog.declaredFunc(typeparams.OriginMethod(obj)) -} - -// FuncValue returns the concrete Function denoted by the source-level -// named function obj, or nil if obj denotes an interface method. -// -// TODO(adonovan): check the invariant that obj.Type() matches the -// result's Signature, both in the params/results and in the receiver. +// FuncValue returns the SSA function or (non-interface) method +// denoted by the specified func symbol. It returns nil id the symbol +// denotes an interface method, or belongs to a package that was not +// created by prog.CreatePackage. func (prog *Program) FuncValue(obj *types.Func) *Function { fn, _ := prog.packageLevelMember(obj).(*Function) return fn } -// ConstValue returns the SSA Value denoted by the source-level named -// constant obj. +// ConstValue returns the SSA constant denoted by the specified const symbol. func (prog *Program) ConstValue(obj *types.Const) *Const { // TODO(adonovan): opt: share (don't reallocate) // Consts for const objects and constant ast.Exprs. @@ -221,7 +218,7 @@ func (prog *Program) ConstValue(obj *types.Const) *Const { } // VarValue returns the SSA Value that corresponds to a specific -// identifier denoting the source-level named variable obj. +// identifier denoting the specified var symbol. // // VarValue returns nil if a local variable was not found, perhaps // because its package was not built, the debug information was not diff --git a/vendor/golang.org/x/tools/go/ssa/ssa.go b/vendor/golang.org/x/tools/go/ssa/ssa.go index c3471c156..30bf4bc67 100644 --- a/vendor/golang.org/x/tools/go/ssa/ssa.go +++ b/vendor/golang.org/x/tools/go/ssa/ssa.go @@ -23,20 +23,25 @@ import ( type Program struct { Fset *token.FileSet // position information for the files of this Program imported map[string]*Package // all importable Packages, keyed by import path - packages map[*types.Package]*Package // all loaded Packages, keyed by object + packages map[*types.Package]*Package // all created Packages mode BuilderMode // set of mode bits for SSA construction MethodSets typeutil.MethodSetCache // cache of type-checker's method-sets - canon *canonizer // type canonicalization map - ctxt *typeparams.Context // cache for type checking instantiations + canon *canonizer // type canonicalization map + ctxt *types.Context // cache for type checking instantiations - methodsMu sync.Mutex // guards the following maps: - methodSets typeutil.Map // maps type to its concrete methodSet - runtimeTypes typeutil.Map // types for which rtypes are needed - bounds map[boundsKey]*Function // bounds for curried x.Method closures - thunks map[selectionKey]*Function // thunks for T.Method expressions - instances map[*Function]*instanceSet // instances of generic functions - parameterized tpWalker // determines whether a type reaches a type parameter. + methodsMu sync.Mutex + methodSets typeutil.Map // maps type to its concrete *methodSet + + parameterized tpWalker // memoization of whether a type refers to type parameters + + runtimeTypesMu sync.Mutex + runtimeTypes typeutil.Map // set of runtime types (from MakeInterface) + + // objectMethods is a memoization of objectMethod + // to avoid creation of duplicate methods from type information. + objectMethodsMu sync.Mutex + objectMethods map[*types.Func]*Function } // A Package is a single analyzed Go package containing Members for @@ -51,17 +56,19 @@ type Package struct { Prog *Program // the owning program Pkg *types.Package // the corresponding go/types.Package Members map[string]Member // all package members keyed by name (incl. init and init#%d) - objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function. + objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function (values but not types) init *Function // Func("init"); the package's init function debug bool // include full debug info in this package + syntax bool // package was loaded from syntax // The following fields are set transiently, then cleared // after building. - buildOnce sync.Once // ensures package building occurs once - ninit int32 // number of init functions - info *types.Info // package type information - files []*ast.File // package ASTs - created creator // members created as a result of building this package (includes declared functions, wrappers) + buildOnce sync.Once // ensures package building occurs once + ninit int32 // number of init functions + info *types.Info // package type information + files []*ast.File // package ASTs + created creator // members created as a result of building this package (includes declared functions, wrappers) + initVersion map[ast.Expr]string // goversion to use for each global var init expr } // A Member is a member of a Go package, implemented by *NamedConst, @@ -258,8 +265,8 @@ type Node interface { // or method. // // If Blocks is nil, this indicates an external function for which no -// Go source code is available. In this case, FreeVars and Locals -// are nil too. Clients performing whole-program analysis must +// Go source code is available. In this case, FreeVars, Locals, and +// Params are nil too. Clients performing whole-program analysis must // handle external functions specially. // // Blocks contains the function's control-flow graph (CFG). @@ -296,8 +303,8 @@ type Node interface { // // A generic function is a function or method that has uninstantiated type // parameters (TypeParams() != nil). Consider a hypothetical generic -// method, (*Map[K,V]).Get. It may be instantiated with all ground -// (non-parameterized) types as (*Map[string,int]).Get or with +// method, (*Map[K,V]).Get. It may be instantiated with all +// non-parameterized types as (*Map[string,int]).Get or with // parameterized types as (*Map[string,U]).Get, where U is a type parameter. // In both instantiations, Origin() refers to the instantiated generic // method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of @@ -305,39 +312,45 @@ type Node interface { // respectively, and is nil in the generic method. type Function struct { name string - object types.Object // a declared *types.Func or one of its wrappers - method *selection // info about provenance of synthetic methods; thunk => non-nil + object *types.Func // symbol for declared function (nil for FuncLit or synthetic init) + method *selection // info about provenance of synthetic methods; thunk => non-nil Signature *types.Signature pos token.Pos - Synthetic string // provenance of synthetic function; "" for true source functions - syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode - parent *Function // enclosing function if anon; nil if global - Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error) - Prog *Program // enclosing program + // source information + Synthetic string // provenance of synthetic function; "" for true source functions + syntax ast.Node // *ast.Func{Decl,Lit}, if from syntax (incl. generic instances) + info *types.Info // type annotations (iff syntax != nil) + goversion string // Go version of syntax (NB: init is special) + + build buildFunc // algorithm to build function body (nil => built) + parent *Function // enclosing function if anon; nil if global + Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error) + Prog *Program // enclosing program + + // These fields are populated only when the function body is built: + Params []*Parameter // function parameters; for methods, includes receiver FreeVars []*FreeVar // free variables whose values must be supplied by closure - Locals []*Alloc // local variables of this function + Locals []*Alloc // frame-allocated variables of this function Blocks []*BasicBlock // basic blocks of the function; nil => external Recover *BasicBlock // optional; control transfers here after recovered panic AnonFuncs []*Function // anonymous functions directly beneath this one referrers []Instruction // referring instructions (iff Parent() != nil) - built bool // function has completed both CREATE and BUILD phase. anonIdx int32 // position of a nested function in parent's AnonFuncs. fn.Parent()!=nil => fn.Parent().AnonFunc[fn.anonIdx] == fn. - typeparams *typeparams.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function - typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function - topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil. + typeparams *types.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function + typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function + topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil. + generic *generic // instances of this function, if generic - // The following fields are set transiently during building, - // then cleared. + // The following fields are cleared after building. currentBlock *BasicBlock // where to emit code - objects map[types.Object]Value // addresses of local variables + vars map[*types.Var]Value // addresses of local variables namedResults []*Alloc // tuple of named results targets *targets // linked stack of branch targets - lblocks map[types.Object]*lblock // labelled blocks - info *types.Info // *types.Info to build from. nil for wrappers. - subst *subster // non-nil => expand generic body using this type substitution of ground types + lblocks map[*types.Label]*lblock // labelled blocks + subst *subster // type parameter substitutions (if non-nil) } // BasicBlock represents an SSA basic block. @@ -402,9 +415,8 @@ type FreeVar struct { // A Parameter represents an input parameter of a function. type Parameter struct { name string - object types.Object // a *types.Var; nil for non-source locals + object *types.Var // non-nil typ types.Type - pos token.Pos parent *Function referrers []Instruction } @@ -482,15 +494,12 @@ type Builtin struct { // type of the allocated variable is actually // Type().Underlying().(*types.Pointer).Elem(). // -// If Heap is false, Alloc allocates space in the function's -// activation record (frame); we refer to an Alloc(Heap=false) as a -// "local" alloc. Each local Alloc returns the same address each time -// it is executed within the same activation; the space is -// re-initialized to zero. +// If Heap is false, Alloc zero-initializes the same local variable in +// the call frame and returns its address; in this case the Alloc must +// be present in Function.Locals. We call this a "local" alloc. // -// If Heap is true, Alloc allocates space in the heap; we -// refer to an Alloc(Heap=true) as a "new" alloc. Each new Alloc -// returns a different address each time it is executed. +// If Heap is true, Alloc allocates a new zero-initialized variable +// each time the instruction is executed. We call this a "new" alloc. // // When Alloc is applied to a channel, map or slice type, it returns // the address of an uninitialized (nil) reference of that kind; store @@ -681,8 +690,8 @@ type Convert struct { type MultiConvert struct { register X Value - from []*typeparams.Term - to []*typeparams.Term + from []*types.Term + to []*types.Term } // ChangeInterface constructs a value of one interface type from a @@ -865,7 +874,7 @@ type Slice struct { type FieldAddr struct { register X Value // *struct - Field int // field is typeparams.CoreType(X.Type().Underlying().(*types.Pointer).Elem()).(*types.Struct).Field(Field) + Field int // index into CoreType(CoreType(X.Type()).(*types.Pointer).Elem()).(*types.Struct).Fields } // The Field instruction yields the Field of struct X. @@ -884,7 +893,7 @@ type FieldAddr struct { type Field struct { register X Value // struct - Field int // index into typeparams.CoreType(X.Type()).(*types.Struct).Fields + Field int // index into CoreType(X.Type()).(*types.Struct).Fields } // The IndexAddr instruction yields the address of the element at @@ -1068,11 +1077,12 @@ type Next struct { // Type() reflects the actual type of the result, possibly a // 2-types.Tuple; AssertedType is the asserted type. // -// Pos() returns the ast.CallExpr.Lparen if the instruction arose from -// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the -// instruction arose from an explicit e.(T) operation; or the -// ast.CaseClause.Case if the instruction arose from a case of a -// type-switch statement. +// Depending on the TypeAssert's purpose, Pos may return: +// - the ast.CallExpr.Lparen of an explicit T(e) conversion; +// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation; +// - the ast.CaseClause.Case of a case of a type-switch statement; +// - the Ident(m).NamePos of an interface method value i.m +// (for which TypeAssert may be used to effect the nil check). // // Example printed form: // @@ -1390,7 +1400,7 @@ type anInstruction struct { // represents a dynamically dispatched call to an interface method. // In this mode, Value is the interface value and Method is the // interface's abstract method. The interface value may be a type -// parameter. Note: an abstract method may be shared by multiple +// parameter. Note: an interface method may be shared by multiple // interfaces due to embedding; Value.Type() provides the specific // interface used for this call. // @@ -1408,7 +1418,7 @@ type anInstruction struct { // the last element of Args is a slice. type CallCommon struct { Value Value // receiver (invoke mode) or func value (call mode) - Method *types.Func // abstract method (invoke mode) + Method *types.Func // interface method (invoke mode) Args []Value // actual parameters (in static method call, includes receiver) pos token.Pos // position of CallExpr.Lparen, iff explicit in source } @@ -1507,14 +1517,19 @@ func (v *Global) String() string { return v.RelString(nil) func (v *Global) Package() *Package { return v.Pkg } func (v *Global) RelString(from *types.Package) string { return relString(v, from) } -func (v *Function) Name() string { return v.name } -func (v *Function) Type() types.Type { return v.Signature } -func (v *Function) Pos() token.Pos { return v.pos } -func (v *Function) Token() token.Token { return token.FUNC } -func (v *Function) Object() types.Object { return v.object } -func (v *Function) String() string { return v.RelString(nil) } -func (v *Function) Package() *Package { return v.Pkg } -func (v *Function) Parent() *Function { return v.parent } +func (v *Function) Name() string { return v.name } +func (v *Function) Type() types.Type { return v.Signature } +func (v *Function) Pos() token.Pos { return v.pos } +func (v *Function) Token() token.Token { return token.FUNC } +func (v *Function) Object() types.Object { + if v.object != nil { + return types.Object(v.object) + } + return nil +} +func (v *Function) String() string { return v.RelString(nil) } +func (v *Function) Package() *Package { return v.Pkg } +func (v *Function) Parent() *Function { return v.parent } func (v *Function) Referrers() *[]Instruction { if v.parent != nil { return &v.referrers @@ -1524,10 +1539,7 @@ func (v *Function) Referrers() *[]Instruction { // TypeParams are the function's type parameters if generic or the // type parameters that were instantiated if fn is an instantiation. -// -// TODO(taking): declare result type as *types.TypeParamList -// after we drop support for go1.17. -func (fn *Function) TypeParams() *typeparams.TypeParamList { +func (fn *Function) TypeParams() *types.TypeParamList { return fn.typeparams } @@ -1535,12 +1547,25 @@ func (fn *Function) TypeParams() *typeparams.TypeParamList { // from fn.Origin(). func (fn *Function) TypeArgs() []types.Type { return fn.typeargs } -// Origin is the function fn is an instantiation of. Returns nil if fn is not -// an instantiation. +// Origin returns the generic function from which fn was instantiated, +// or nil if fn is not an instantiation. func (fn *Function) Origin() *Function { if fn.parent != nil && len(fn.typeargs) > 0 { - // Nested functions are BUILT at a different time than there instances. - return fn.parent.Origin().AnonFuncs[fn.anonIdx] + // Nested functions are BUILT at a different time than their instances. + // Build declared package if not yet BUILT. This is not an expected use + // case, but is simple and robust. + fn.declaredPackage().Build() + } + return origin(fn) +} + +// origin is the function that fn is an instantiation of. Returns nil if fn is +// not an instantiation. +// +// Precondition: fn and the origin function are done building. +func origin(fn *Function) *Function { + if fn.parent != nil && len(fn.typeargs) > 0 { + return origin(fn.parent).AnonFuncs[fn.anonIdx] } return fn.topLevelOrigin } @@ -1549,7 +1574,7 @@ func (v *Parameter) Type() types.Type { return v.typ } func (v *Parameter) Name() string { return v.name } func (v *Parameter) Object() types.Object { return v.object } func (v *Parameter) Referrers() *[]Instruction { return &v.referrers } -func (v *Parameter) Pos() token.Pos { return v.pos } +func (v *Parameter) Pos() token.Pos { return v.object.Pos() } func (v *Parameter) Parent() *Function { return v.parent } func (v *Alloc) Type() types.Type { return v.typ } diff --git a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go index 96d69a20a..3daa67a07 100644 --- a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go +++ b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go @@ -14,14 +14,14 @@ import ( "golang.org/x/tools/go/loader" "golang.org/x/tools/go/packages" "golang.org/x/tools/go/ssa" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) // Packages creates an SSA program for a set of packages. // // The packages must have been loaded from source syntax using the -// golang.org/x/tools/go/packages.Load function in LoadSyntax or -// LoadAllSyntax mode. +// [packages.Load] function in [packages.LoadSyntax] or +// [packages.LoadAllSyntax] mode. // // Packages creates an SSA package for each well-typed package in the // initial list, plus all their dependencies. The resulting list of @@ -29,12 +29,30 @@ import ( // a nil if SSA code could not be constructed for the corresponding initial // package due to type errors. // -// Code for bodies of functions is not built until Build is called on -// the resulting Program. SSA code is constructed only for the initial -// packages with well-typed syntax trees. +// Code for bodies of functions is not built until [Program.Build] is +// called on the resulting Program. SSA code is constructed only for +// the initial packages with well-typed syntax trees. // // The mode parameter controls diagnostics and checking during SSA construction. func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) { + // TODO(adonovan): opt: this calls CreatePackage far more than + // necessary: for all dependencies, not just the (non-initial) + // direct dependencies of the initial packages. + // + // But can it reasonably be changed without breaking the + // spirit and/or letter of the law above? Clients may notice + // if we call CreatePackage less, as methods like + // Program.FuncValue will return nil. Or must we provide a new + // function (and perhaps deprecate this one)? Is it worth it? + // + // Tim King makes the interesting point that it would be + // possible to entirely alleviate the client from the burden + // of calling CreatePackage for non-syntax packages, if we + // were to treat vars and funcs lazily in the same way we now + // treat methods. (In essence, try to move away from the + // notion of ssa.Packages, and make the Program answer + // all reasonable questions about any types.Object.) + return doPackages(initial, mode, false) } @@ -42,7 +60,7 @@ func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, // their dependencies. // // The packages must have been loaded from source syntax using the -// golang.org/x/tools/go/packages.Load function in LoadAllSyntax mode. +// [packages.Load] function in [packages.LoadAllSyntax] mode. // // AllPackages creates an SSA package for each well-typed package in the // initial list, plus all their dependencies. The resulting list of @@ -102,7 +120,7 @@ func doPackages(initial []*packages.Package, mode ssa.BuilderMode, deps bool) (* // // The mode parameter controls diagnostics and checking during SSA construction. // -// Deprecated: Use golang.org/x/tools/go/packages and the Packages +// Deprecated: Use [golang.org/x/tools/go/packages] and the [Packages] // function instead; see ssa.Example_loadPackages. func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program { prog := ssa.NewProgram(lprog.Fset, mode) @@ -116,16 +134,17 @@ func CreateProgram(lprog *loader.Program, mode ssa.BuilderMode) *ssa.Program { return prog } -// BuildPackage builds an SSA program with IR for a single package. +// BuildPackage builds an SSA program with SSA intermediate +// representation (IR) for all functions of a single package. // -// It populates pkg by type-checking the specified file ASTs. All +// It populates pkg by type-checking the specified file syntax trees. All // dependencies are loaded using the importer specified by tc, which // typically loads compiler export data; SSA code cannot be built for -// those packages. BuildPackage then constructs an ssa.Program with all +// those packages. BuildPackage then constructs an [ssa.Program] with all // dependency packages created, and builds and returns the SSA package // corresponding to pkg. // -// The caller must have set pkg.Path() to the import path. +// The caller must have set pkg.Path to the import path. // // The operation fails if there were any type-checking or import errors. // @@ -143,10 +162,11 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil Defs: make(map[*ast.Ident]types.Object), Uses: make(map[*ast.Ident]types.Object), Implicits: make(map[ast.Node]types.Object), + Instances: make(map[*ast.Ident]types.Instance), Scopes: make(map[ast.Node]*types.Scope), Selections: make(map[*ast.SelectorExpr]*types.Selection), } - typeparams.InitInstanceInfo(info) + versions.InitFileVersions(info) if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil { return nil, nil, err } @@ -168,6 +188,25 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil } createAll(pkg.Imports()) + // TODO(adonovan): we could replace createAll with just: + // + // // Create SSA packages for all imports. + // for _, p := range pkg.Imports() { + // prog.CreatePackage(p, nil, nil, true) + // } + // + // (with minor changes to changes to ../builder_test.go as + // shown in CL 511715 PS 10.) But this would strictly violate + // the letter of the doc comment above, which says "all + // dependencies created". + // + // Tim makes the good point with some extra work we could + // remove the need for any CreatePackage calls except the + // ones with syntax (i.e. primary packages). Of course + // You wouldn't have ssa.Packages and Members for as + // many things but no-one really uses that anyway. + // I wish I had done this from the outset. + // Create and build the primary package. ssapkg := prog.CreatePackage(pkg, files, info, false) ssapkg.Build() diff --git a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go index 5f27050b0..b4feb42cb 100644 --- a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go +++ b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go @@ -4,7 +4,14 @@ package ssautil // import "golang.org/x/tools/go/ssa/ssautil" -import "golang.org/x/tools/go/ssa" +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/ssa" + + _ "unsafe" // for linkname hack +) // This file defines utilities for visiting the SSA representation of // a Program. @@ -18,50 +25,113 @@ import "golang.org/x/tools/go/ssa" // synthetic wrappers. // // Precondition: all packages are built. +// +// TODO(adonovan): this function is underspecified. It doesn't +// actually work like a linker, which computes reachability from main +// using something like go/callgraph/cha (without materializing the +// call graph). In fact, it treats all public functions and all +// methods of public non-parameterized types as roots, even though +// they may be unreachable--but only in packages created from syntax. +// +// I think we should deprecate AllFunctions function in favor of two +// clearly defined ones: +// +// 1. The first would efficiently compute CHA reachability from a set +// of main packages, making it suitable for a whole-program +// analysis context with InstantiateGenerics, in conjunction with +// Program.Build. +// +// 2. The second would return only the set of functions corresponding +// to source Func{Decl,Lit} syntax, like SrcFunctions in +// go/analysis/passes/buildssa; this is suitable for +// package-at-a-time (or handful of packages) context. +// ssa.Package could easily expose it as a field. +// +// We could add them unexported for now and use them via the linkname hack. func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool { - visit := visitor{ - prog: prog, - seen: make(map[*ssa.Function]bool), + seen := make(map[*ssa.Function]bool) + + var function func(fn *ssa.Function) + function = func(fn *ssa.Function) { + if !seen[fn] { + seen[fn] = true + var buf [10]*ssa.Value // avoid alloc in common case + for _, b := range fn.Blocks { + for _, instr := range b.Instrs { + for _, op := range instr.Operands(buf[:0]) { + if fn, ok := (*op).(*ssa.Function); ok { + function(fn) + } + } + } + } + } } - visit.program() - return visit.seen -} -type visitor struct { - prog *ssa.Program - seen map[*ssa.Function]bool -} + // TODO(adonovan): opt: provide a way to share a builder + // across a sequence of MethodValue calls. -func (visit *visitor) program() { - for _, pkg := range visit.prog.AllPackages() { - for _, mem := range pkg.Members { - if fn, ok := mem.(*ssa.Function); ok { - visit.function(fn) + methodsOf := func(T types.Type) { + if !types.IsInterface(T) { + mset := prog.MethodSets.MethodSet(T) + for i := 0; i < mset.Len(); i++ { + function(prog.MethodValue(mset.At(i))) } } } - for _, T := range visit.prog.RuntimeTypes() { - mset := visit.prog.MethodSets.MethodSet(T) - for i, n := 0, mset.Len(); i < n; i++ { - visit.function(visit.prog.MethodValue(mset.At(i))) + + // Historically, Program.RuntimeTypes used to include the type + // of any exported member of a package loaded from syntax that + // has a non-parameterized type, plus all types + // reachable from that type using reflection, even though + // these runtime types may not be required for them. + // + // Rather than break existing programs that rely on + // AllFunctions visiting extra methods that are unreferenced + // by IR and unreachable via reflection, we moved the logic + // here, unprincipled though it is. + // (See doc comment for better ideas.) + // + // Nonetheless, after the move, we no longer visit every + // method of any type recursively reachable from T, only the + // methods of T and *T themselves, and we only apply this to + // named types T, and not to the type of every exported + // package member. + exportedTypeHack := func(t *ssa.Type) { + if isSyntactic(t.Package()) && + ast.IsExported(t.Name()) && + !types.IsInterface(t.Type()) { + // Consider only named types. + // (Ignore aliases and unsafe.Pointer.) + if named, ok := t.Type().(*types.Named); ok { + if named.TypeParams() == nil { + methodsOf(named) // T + methodsOf(types.NewPointer(named)) // *T + } + } } } -} -func (visit *visitor) function(fn *ssa.Function) { - if !visit.seen[fn] { - visit.seen[fn] = true - var buf [10]*ssa.Value // avoid alloc in common case - for _, b := range fn.Blocks { - for _, instr := range b.Instrs { - for _, op := range instr.Operands(buf[:0]) { - if fn, ok := (*op).(*ssa.Function); ok { - visit.function(fn) - } - } + for _, pkg := range prog.AllPackages() { + for _, mem := range pkg.Members { + switch mem := mem.(type) { + case *ssa.Function: + // Visit all package-level declared functions. + function(mem) + + case *ssa.Type: + exportedTypeHack(mem) } } } + + // Visit all methods of types for which runtime types were + // materialized, as they are reachable through reflection. + for _, T := range prog.RuntimeTypes() { + methodsOf(T) + } + + return seen } // MainPackages returns the subset of the specified packages @@ -76,3 +146,12 @@ func MainPackages(pkgs []*ssa.Package) []*ssa.Package { } return mains } + +// TODO(adonovan): propose a principled API for this. One possibility +// is a new field, Package.SrcFunctions []*Function, which would +// contain the list of SrcFunctions described in point 2 of the +// AllFunctions doc comment, or nil if the package is not from syntax. +// But perhaps overloading nil vs empty slice is too subtle. +// +//go:linkname isSyntactic golang.org/x/tools/go/ssa.isSyntactic +func isSyntactic(pkg *ssa.Package) bool diff --git a/vendor/golang.org/x/tools/go/ssa/subst.go b/vendor/golang.org/x/tools/go/ssa/subst.go index 7efab3578..a9a6d41e8 100644 --- a/vendor/golang.org/x/tools/go/ssa/subst.go +++ b/vendor/golang.org/x/tools/go/ssa/subst.go @@ -6,8 +6,6 @@ package ssa import ( "go/types" - - "golang.org/x/tools/internal/typeparams" ) // Type substituter for a fixed set of replacement types. @@ -18,11 +16,11 @@ import ( // // Not concurrency-safe. type subster struct { - replacements map[*typeparams.TypeParam]types.Type // values should contain no type params - cache map[types.Type]types.Type // cache of subst results - ctxt *typeparams.Context // cache for instantiation - scope *types.Scope // *types.Named declared within this scope can be substituted (optional) - debug bool // perform extra debugging checks + replacements map[*types.TypeParam]types.Type // values should contain no type params + cache map[types.Type]types.Type // cache of subst results + ctxt *types.Context // cache for instantiation + scope *types.Scope // *types.Named declared within this scope can be substituted (optional) + debug bool // perform extra debugging checks // TODO(taking): consider adding Pos // TODO(zpavlinovic): replacements can contain type params // when generating instances inside of a generic function body. @@ -31,11 +29,11 @@ type subster struct { // Returns a subster that replaces tparams[i] with targs[i]. Uses ctxt as a cache. // targs should not contain any types in tparams. // scope is the (optional) lexical block of the generic function for which we are substituting. -func makeSubster(ctxt *typeparams.Context, scope *types.Scope, tparams *typeparams.TypeParamList, targs []types.Type, debug bool) *subster { +func makeSubster(ctxt *types.Context, scope *types.Scope, tparams *types.TypeParamList, targs []types.Type, debug bool) *subster { assert(tparams.Len() == len(targs), "makeSubster argument count must match") subst := &subster{ - replacements: make(map[*typeparams.TypeParam]types.Type, tparams.Len()), + replacements: make(map[*types.TypeParam]types.Type, tparams.Len()), cache: make(map[types.Type]types.Type), ctxt: ctxt, scope: scope, @@ -82,7 +80,7 @@ func (subst *subster) typ(t types.Type) (res types.Type) { // fall through if result r will be identical to t, types.Identical(r, t). switch t := t.(type) { - case *typeparams.TypeParam: + case *types.TypeParam: r := subst.replacements[t] assert(r != nil, "type param without replacement encountered") return r @@ -131,7 +129,7 @@ func (subst *subster) typ(t types.Type) (res types.Type) { case *types.Signature: return subst.signature(t) - case *typeparams.Union: + case *types.Union: return subst.union(t) case *types.Interface: @@ -220,25 +218,25 @@ func (subst *subster) var_(v *types.Var) *types.Var { return v } -func (subst *subster) union(u *typeparams.Union) *typeparams.Union { - var out []*typeparams.Term // nil => no updates +func (subst *subster) union(u *types.Union) *types.Union { + var out []*types.Term // nil => no updates for i, n := 0, u.Len(); i < n; i++ { t := u.Term(i) r := subst.typ(t.Type()) if r != t.Type() && out == nil { - out = make([]*typeparams.Term, n) + out = make([]*types.Term, n) for j := 0; j < i; j++ { out[j] = u.Term(j) } } if out != nil { - out[i] = typeparams.NewTerm(t.Tilde(), r) + out[i] = types.NewTerm(t.Tilde(), r) } } if out != nil { - return typeparams.NewUnion(out) + return types.NewUnion(out) } return u } @@ -249,7 +247,7 @@ func (subst *subster) interface_(iface *types.Interface) *types.Interface { } // methods for the interface. Initially nil if there is no known change needed. - // Signatures for the method where recv is nil. NewInterfaceType fills in the recievers. + // Signatures for the method where recv is nil. NewInterfaceType fills in the receivers. var methods []*types.Func initMethods := func(n int) { // copy first n explicit methods methods = make([]*types.Func, iface.NumExplicitMethods()) @@ -262,7 +260,7 @@ func (subst *subster) interface_(iface *types.Interface) *types.Interface { for i := 0; i < iface.NumExplicitMethods(); i++ { f := iface.ExplicitMethod(i) // On interfaces, we need to cycle break on anonymous interface types - // being in a cycle with their signatures being in cycles with their recievers + // being in a cycle with their signatures being in cycles with their receivers // that do not go through a Named. norecv := changeRecv(f.Type().(*types.Signature), nil) sig := subst.typ(norecv) @@ -310,7 +308,7 @@ func (subst *subster) named(t *types.Named) types.Type { // (2) locally scoped type, // (3) generic (type parameters but no type arguments), or // (4) instantiated (type parameters and type arguments). - tparams := typeparams.ForNamed(t) + tparams := t.TypeParams() if tparams.Len() == 0 { if subst.scope != nil && !subst.scope.Contains(t.Obj().Pos()) { // Outside the current function scope? @@ -344,7 +342,7 @@ func (subst *subster) named(t *types.Named) types.Type { n.SetUnderlying(subst.typ(t.Underlying())) return n } - targs := typeparams.NamedTypeArgs(t) + targs := t.TypeArgs() // insts are arguments to instantiate using. insts := make([]types.Type, tparams.Len()) @@ -367,13 +365,13 @@ func (subst *subster) named(t *types.Named) types.Type { inst := subst.typ(targs.At(i)) // TODO(generic): Check with rfindley for mutual recursion insts[i] = inst } - r, err := typeparams.Instantiate(subst.ctxt, typeparams.NamedTypeOrigin(t), insts, false) + r, err := types.Instantiate(subst.ctxt, t.Origin(), insts, false) assert(err == nil, "failed to Instantiate Named type") return r } func (subst *subster) signature(t *types.Signature) types.Type { - tparams := typeparams.ForSignature(t) + tparams := t.TypeParams() // We are choosing not to support tparams.Len() > 0 until a need has been observed in practice. // @@ -388,7 +386,7 @@ func (subst *subster) signature(t *types.Signature) types.Type { // no type params to substitute // (2)generic method and recv needs to be substituted. - // Recievers can be either: + // Receivers can be either: // named // pointer to named // interface @@ -398,7 +396,7 @@ func (subst *subster) signature(t *types.Signature) types.Type { params := subst.tuple(t.Params()) results := subst.tuple(t.Results()) if recv != t.Recv() || params != t.Params() || results != t.Results() { - return typeparams.NewSignatureType(recv, nil, nil, params, results, t.Variadic()) + return types.NewSignatureType(recv, nil, nil, params, results, t.Variadic()) } return t } @@ -422,7 +420,7 @@ func reaches(t types.Type, c map[types.Type]bool) (res bool) { }() switch t := t.(type) { - case *typeparams.TypeParam, *types.Basic: + case *types.TypeParam, *types.Basic: return false case *types.Array: return reaches(t.Elem(), c) @@ -451,7 +449,7 @@ func reaches(t types.Type, c map[types.Type]bool) (res bool) { return true } return reaches(t.Params(), c) || reaches(t.Results(), c) - case *typeparams.Union: + case *types.Union: for i := 0; i < t.Len(); i++ { if reaches(t.Term(i).Type(), c) { return true diff --git a/vendor/golang.org/x/tools/go/ssa/util.go b/vendor/golang.org/x/tools/go/ssa/util.go index db53aebee..6e9f1282b 100644 --- a/vendor/golang.org/x/tools/go/ssa/util.go +++ b/vendor/golang.org/x/tools/go/ssa/util.go @@ -43,12 +43,6 @@ func isBlankIdent(e ast.Expr) bool { //// Type utilities. Some of these belong in go/types. -// isPointer returns true for types whose underlying type is a pointer. -func isPointer(typ types.Type) bool { - _, ok := typ.Underlying().(*types.Pointer) - return ok -} - // isNonTypeParamInterface reports whether t is an interface type but not a type parameter. func isNonTypeParamInterface(t types.Type) bool { return !typeparams.IsTypeParam(t) && types.IsInterface(t) @@ -100,12 +94,33 @@ func isBasicConvTypes(tset termList) bool { return all && basics >= 1 && tset.Len()-basics <= 1 } -// deref returns a pointer's element type; otherwise it returns typ. -func deref(typ types.Type) types.Type { +// deptr returns a pointer's element type and true; otherwise it returns (typ, false). +// This function is oblivious to core types and is not suitable for generics. +// +// TODO: Deprecate this function once all usages have been audited. +func deptr(typ types.Type) (types.Type, bool) { if p, ok := typ.Underlying().(*types.Pointer); ok { - return p.Elem() + return p.Elem(), true } - return typ + return typ, false +} + +// deref returns the element type of a type with a pointer core type and true; +// otherwise it returns (typ, false). +func deref(typ types.Type) (types.Type, bool) { + if p, ok := typeparams.CoreType(typ).(*types.Pointer); ok { + return p.Elem(), true + } + return typ, false +} + +// mustDeref returns the element type of a type with a pointer core type. +// Panics on failure. +func mustDeref(typ types.Type) types.Type { + if et, ok := deref(typ); ok { + return et + } + panic("cannot dereference type " + typ.String()) } // recvType returns the receiver type of method obj. @@ -113,6 +128,17 @@ func recvType(obj *types.Func) types.Type { return obj.Type().(*types.Signature).Recv().Type() } +// fieldOf returns the index'th field of the (core type of) a struct type; +// otherwise returns nil. +func fieldOf(typ types.Type, index int) *types.Var { + if st, ok := typeparams.CoreType(typ).(*types.Struct); ok { + if 0 <= index && index < st.NumFields() { + return st.Field(index) + } + } + return nil +} + // isUntyped returns true for types that are untyped. func isUntyped(typ types.Type) bool { b, ok := typ.(*types.Basic) @@ -154,39 +180,19 @@ func makeLen(T types.Type) *Builtin { } } -// nonbasicTypes returns a list containing all of the types T in ts that are non-basic. -func nonbasicTypes(ts []types.Type) []types.Type { - if len(ts) == 0 { - return nil - } - added := make(map[types.Type]bool) // additionally filter duplicates - var filtered []types.Type - for _, T := range ts { - if !isBasic(T) { - if !added[T] { - added[T] = true - filtered = append(filtered, T) - } - } - } - return filtered -} - -// receiverTypeArgs returns the type arguments to a function's reciever. -// Returns an empty list if obj does not have a reciever or its reciever does not have type arguments. +// receiverTypeArgs returns the type arguments to a function's receiver. +// Returns an empty list if obj does not have a receiver or its receiver does not have type arguments. func receiverTypeArgs(obj *types.Func) []types.Type { rtype := recvType(obj) if rtype == nil { return nil } - if isPointer(rtype) { - rtype = rtype.(*types.Pointer).Elem() - } + rtype, _ = deptr(rtype) named, ok := rtype.(*types.Named) if !ok { return nil } - ts := typeparams.NamedTypeArgs(named) + ts := named.TypeArgs() if ts.Len() == 0 { return nil } @@ -205,7 +211,7 @@ func recvAsFirstArg(sig *types.Signature) *types.Signature { for i := 0; i < sig.Params().Len(); i++ { params = append(params, sig.Params().At(i)) } - return typeparams.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) + return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) } // instance returns whether an expression is a simple or qualified identifier @@ -222,13 +228,13 @@ func instance(info *types.Info, expr ast.Expr) bool { default: return false } - _, ok := typeparams.GetInstances(info)[id] + _, ok := info.Instances[id] return ok } // instanceArgs returns the Instance[id].TypeArgs as a slice. func instanceArgs(info *types.Info, id *ast.Ident) []types.Type { - targList := typeparams.GetInstances(info)[id].TypeArgs + targList := info.Instances[id].TypeArgs if targList == nil { return nil } @@ -280,7 +286,7 @@ func (c *canonizer) Type(T types.Type) types.Type { return T } -// A type for representating an canonized list of types. +// A type for representing a canonized list of types. type typeList []types.Type func (l *typeList) identical(ts []types.Type) bool { @@ -346,13 +352,13 @@ func (m *typeListMap) hash(ts []types.Type) uint32 { } // instantiateMethod instantiates m with targs and returns a canonical representative for this method. -func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *typeparams.Context) *types.Func { +func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func { recv := recvType(m) if p, ok := recv.(*types.Pointer); ok { recv = p.Elem() } named := recv.(*types.Named) - inst, err := typeparams.Instantiate(ctxt, typeparams.NamedTypeOrigin(named), targs, false) + inst, err := types.Instantiate(ctxt, named.Origin(), targs, false) if err != nil { panic(err) } @@ -360,3 +366,16 @@ func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctx obj, _, _ := types.LookupFieldOrMethod(rep, true, m.Pkg(), m.Name()) return obj.(*types.Func) } + +// Exposed to ssautil using the linkname hack. +func isSyntactic(pkg *Package) bool { return pkg.syntax } + +// mapValues returns a new unordered array of map values. +func mapValues[K comparable, V any](m map[K]V) []V { + vals := make([]V, 0, len(m)) + for _, fn := range m { + vals = append(vals, fn) + } + return vals + +} diff --git a/vendor/golang.org/x/tools/go/ssa/wrappers.go b/vendor/golang.org/x/tools/go/ssa/wrappers.go index 228daf615..7c7ee4099 100644 --- a/vendor/golang.org/x/tools/go/ssa/wrappers.go +++ b/vendor/golang.org/x/tools/go/ssa/wrappers.go @@ -28,7 +28,7 @@ import ( // -- wrappers ----------------------------------------------------------- -// makeWrapper returns a synthetic method that delegates to the +// createWrapper returns a synthetic method that delegates to the // declared method denoted by meth.Obj(), first performing any // necessary pointer indirections or field selections implied by meth. // @@ -40,21 +40,17 @@ import ( // - optional implicit field selections // - meth.Obj() may denote a concrete or an interface method // - the result may be a thunk or a wrapper. -// -// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) -func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { +func createWrapper(prog *Program, sel *selection, cr *creator) *Function { obj := sel.obj.(*types.Func) // the declared function sig := sel.typ.(*types.Signature) // type of this wrapper var recv *types.Var // wrapper's receiver or thunk's params[0] name := obj.Name() var description string - var start int // first regular param if sel.kind == types.MethodExpr { name += "$thunk" description = "thunk" recv = sig.Params().At(0) - start = 1 } else { description = "wrapper" recv = sig.Recv() @@ -62,8 +58,9 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { description = fmt.Sprintf("%s for %s", description, sel.obj) if prog.mode&LogSource != 0 { - defer logStack("make %s to (%s)", description, recv.Type())() + defer logStack("create %s to (%s)", description, recv.Type())() } + /* method wrapper */ fn := &Function{ name: name, method: sel, @@ -72,33 +69,53 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { Synthetic: description, Prog: prog, pos: obj.Pos(), - info: nil, // info is not set on wrappers. + // wrappers have no syntax + build: (*builder).buildWrapper, + syntax: nil, + info: nil, + goversion: "", } cr.Add(fn) + return fn +} + +// buildWrapper builds fn.Body for a method wrapper. +func (b *builder) buildWrapper(fn *Function) { + var recv *types.Var // wrapper's receiver or thunk's params[0] + var start int // first regular param + if fn.method.kind == types.MethodExpr { + recv = fn.Signature.Params().At(0) + start = 1 + } else { + recv = fn.Signature.Recv() + } + fn.startBody() fn.addSpilledParam(recv) createParams(fn, start) - indices := sel.index + indices := fn.method.index var v Value = fn.Locals[0] // spilled receiver - if isPointer(sel.recv) { + srdt, ptrRecv := deptr(fn.method.recv) + if ptrRecv { v = emitLoad(fn, v) // For simple indirection wrappers, perform an informative nil-check: // "value method (T).f called using nil *T pointer" - if len(indices) == 1 && !isPointer(recvType(obj)) { + _, ptrObj := deptr(recvType(fn.object)) + if len(indices) == 1 && !ptrObj { var c Call c.Call.Value = &Builtin{ name: "ssa:wrapnilchk", sig: types.NewSignature(nil, - types.NewTuple(anonVar(sel.recv), anonVar(tString), anonVar(tString)), - types.NewTuple(anonVar(sel.recv)), false), + types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)), + types.NewTuple(anonVar(fn.method.recv)), false), } c.Call.Args = []Value{ v, - stringConst(deref(sel.recv).String()), - stringConst(sel.obj.Name()), + stringConst(srdt.String()), + stringConst(fn.method.obj.Name()), } c.setType(v.Type()) v = fn.emit(&c) @@ -120,18 +137,14 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { // address of implicit C field. var c Call - if r := recvType(obj); !types.IsInterface(r) { // concrete method - if !isPointer(r) { + if r := recvType(fn.object); !types.IsInterface(r) { // concrete method + if _, ptrObj := deptr(r); !ptrObj { v = emitLoad(fn, v) } - callee := prog.originFunc(obj) - if callee.typeparams.Len() > 0 { - callee = prog.lookupOrCreateInstance(callee, receiverTypeArgs(obj), cr) - } - c.Call.Value = callee + c.Call.Value = fn.Prog.objectMethod(fn.object, b.created) c.Call.Args = append(c.Call.Args, v) } else { - c.Call.Method = obj + c.Call.Method = fn.object c.Call.Value = emitLoad(fn, v) // interface (possibly a typeparam) } for _, arg := range fn.Params[1:] { @@ -139,8 +152,6 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { } emitTailCall(fn, &c) fn.finishBody() - fn.done() - return fn } // createParams creates parameters for wrapper method fn based on its @@ -149,13 +160,13 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function { func createParams(fn *Function, start int) { tparams := fn.Signature.Params() for i, n := start, tparams.Len(); i < n; i++ { - fn.addParamObj(tparams.At(i)) + fn.addParamVar(tparams.At(i)) } } // -- bounds ----------------------------------------------------------- -// makeBound returns a bound method wrapper (or "bound"), a synthetic +// createBound returns a bound method wrapper (or "bound"), a synthetic // function that delegates to a concrete or interface method denoted // by obj. The resulting function has no receiver, but has one free // variable which will be used as the method's receiver in the @@ -174,66 +185,57 @@ func createParams(fn *Function, start int) { // // f := func() { return t.meth() } // -// Unlike makeWrapper, makeBound need perform no indirection or field +// Unlike createWrapper, createBound need perform no indirection or field // selections because that can be done before the closure is // constructed. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeBound(prog *Program, obj *types.Func, cr *creator) *Function { - targs := receiverTypeArgs(obj) - key := boundsKey{obj, prog.canon.List(targs)} - - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - fn, ok := prog.bounds[key] - if !ok { - description := fmt.Sprintf("bound method wrapper for %s", obj) - if prog.mode&LogSource != 0 { - defer logStack("%s", description)() - } - fn = &Function{ - name: obj.Name() + "$bound", - object: obj, - Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver - Synthetic: description, - Prog: prog, - pos: obj.Pos(), - info: nil, // info is not set on wrappers. - } - cr.Add(fn) - - fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn} - fn.FreeVars = []*FreeVar{fv} - fn.startBody() - createParams(fn, 0) - var c Call - - if !types.IsInterface(recvType(obj)) { // concrete - callee := prog.originFunc(obj) - if callee.typeparams.Len() > 0 { - callee = prog.lookupOrCreateInstance(callee, targs, cr) - } - c.Call.Value = callee - c.Call.Args = []Value{fv} - } else { - c.Call.Method = obj - c.Call.Value = fv // interface (possibly a typeparam) - } - for _, arg := range fn.Params { - c.Call.Args = append(c.Call.Args, arg) - } - emitTailCall(fn, &c) - fn.finishBody() - fn.done() - - prog.bounds[key] = fn +func createBound(prog *Program, obj *types.Func, cr *creator) *Function { + description := fmt.Sprintf("bound method wrapper for %s", obj) + if prog.mode&LogSource != 0 { + defer logStack("%s", description)() + } + /* bound method wrapper */ + fn := &Function{ + name: obj.Name() + "$bound", + object: obj, + Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver + Synthetic: description, + Prog: prog, + pos: obj.Pos(), + // wrappers have no syntax + build: (*builder).buildBound, + syntax: nil, + info: nil, + goversion: "", } + fn.FreeVars = []*FreeVar{{name: "recv", typ: recvType(obj), parent: fn}} // (cyclic) + cr.Add(fn) return fn } +// buildBound builds fn.Body for a bound method closure. +func (b *builder) buildBound(fn *Function) { + fn.startBody() + createParams(fn, 0) + var c Call + + recv := fn.FreeVars[0] + if !types.IsInterface(recvType(fn.object)) { // concrete + c.Call.Value = fn.Prog.objectMethod(fn.object, b.created) + c.Call.Args = []Value{recv} + } else { + c.Call.Method = fn.object + c.Call.Value = recv // interface (possibly a typeparam) + } + for _, arg := range fn.Params { + c.Call.Args = append(c.Call.Args, arg) + } + emitTailCall(fn, &c) + fn.finishBody() +} + // -- thunks ----------------------------------------------------------- -// makeThunk returns a thunk, a synthetic function that delegates to a +// createThunk returns a thunk, a synthetic function that delegates to a // concrete or interface method denoted by sel.obj. The resulting // function has no receiver, but has an additional (first) regular // parameter. @@ -249,38 +251,16 @@ func makeBound(prog *Program, obj *types.Func, cr *creator) *Function { // f is a synthetic wrapper defined as if by: // // f := func(t T) { return t.meth() } -// -// TODO(adonovan): opt: currently the stub is created even when used -// directly in a function call: C.f(i, 0). This is less efficient -// than inlining the stub. -// -// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu) -func makeThunk(prog *Program, sel *selection, cr *creator) *Function { +func createThunk(prog *Program, sel *selection, cr *creator) *Function { if sel.kind != types.MethodExpr { panic(sel) } - // Canonicalize sel.recv to avoid constructing duplicate thunks. - canonRecv := prog.canon.Type(sel.recv) - key := selectionKey{ - kind: sel.kind, - recv: canonRecv, - obj: sel.obj, - index: fmt.Sprint(sel.index), - indirect: sel.indirect, + fn := createWrapper(prog, sel, cr) + if fn.Signature.Recv() != nil { + panic(fn) // unexpected receiver } - prog.methodsMu.Lock() - defer prog.methodsMu.Unlock() - - fn, ok := prog.thunks[key] - if !ok { - fn = makeWrapper(prog, sel, cr) - if fn.Signature.Recv() != nil { - panic(fn) // unexpected receiver - } - prog.thunks[key] = fn - } return fn } @@ -288,21 +268,6 @@ func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic()) } -// selectionKey is like types.Selection but a usable map key. -type selectionKey struct { - kind types.SelectionKind - recv types.Type // canonicalized via Program.canon - obj types.Object - index string - indirect bool -} - -// boundsKey is a unique for the object and a type instantiation. -type boundsKey struct { - obj types.Object // t.meth - inst *typeList // canonical type instantiation list. -} - // A local version of *types.Selection. // Needed for some additional control, such as creating a MethodExpr for an instantiation. type selection struct { @@ -327,16 +292,16 @@ func toSelection(sel *types.Selection) *selection { // -- instantiations -------------------------------------------------- -// buildInstantiationWrapper creates a body for an instantiation +// buildInstantiationWrapper builds the body of an instantiation // wrapper fn. The body calls the original generic function, // bracketed by ChangeType conversions on its arguments and results. -func buildInstantiationWrapper(fn *Function) { +func (b *builder) buildInstantiationWrapper(fn *Function) { orig := fn.topLevelOrigin sig := fn.Signature fn.startBody() if sig.Recv() != nil { - fn.addParamObj(sig.Recv()) + fn.addParamVar(sig.Recv()) } createParams(fn, 0) diff --git a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go index be8f5a867..11d5c8c3a 100644 --- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go +++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go @@ -26,13 +26,10 @@ package objectpath import ( "fmt" "go/types" - "sort" "strconv" "strings" "golang.org/x/tools/internal/typeparams" - - _ "unsafe" // for go:linkname ) // A Path is an opaque name that identifies a types.Object @@ -113,6 +110,19 @@ const ( opObj = 'O' // .Obj() (Named, TypeParam) ) +// For is equivalent to new(Encoder).For(obj). +// +// It may be more efficient to reuse a single Encoder across several calls. +func For(obj types.Object) (Path, error) { + return new(Encoder).For(obj) +} + +// An Encoder amortizes the cost of encoding the paths of multiple objects. +// The zero value of an Encoder is ready to use. +type Encoder struct { + scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects +} + // For returns the path to an object relative to its package, // or an error if the object is not accessible from the package's Scope. // @@ -125,6 +135,17 @@ const ( // These objects are sufficient to define the API of their package. // The objects described by a package's export data are drawn from this set. // +// The set of objects accessible from a package's Scope depends on +// whether the package was produced by type-checking syntax, or +// reading export data; the latter may have a smaller Scope since +// export data trims objects that are not reachable from an exported +// declaration. For example, the For function will return a path for +// an exported method of an unexported type that is not reachable +// from any public declaration; this path will cause the Object +// function to fail if called on a package loaded from export data. +// TODO(adonovan): is this a bug or feature? Should this package +// compute accessibility in the same way? +// // For does not return a path for predeclared names, imported package // names, local names, and unexported package-level names (except // types). @@ -145,24 +166,7 @@ const ( // .Type().Field(0) (field Var X) // // where p is the package (*types.Package) to which X belongs. -func For(obj types.Object) (Path, error) { - return newEncoderFor()(obj) -} - -// An encoder amortizes the cost of encoding the paths of multiple objects. -// Nonexported pending approval of proposal 58668. -type encoder struct { - scopeNamesMemo map[*types.Scope][]string // memoization of Scope.Names() - namedMethodsMemo map[*types.Named][]*types.Func // memoization of namedMethods() -} - -// Exposed to gopls via golang.org/x/tools/internal/typesinternal -// pending approval of proposal 58668. -// -//go:linkname newEncoderFor -func newEncoderFor() func(types.Object) (Path, error) { return new(encoder).For } - -func (enc *encoder) For(obj types.Object) (Path, error) { +func (enc *Encoder) For(obj types.Object) (Path, error) { pkg := obj.Pkg() // This table lists the cases of interest. @@ -219,7 +223,7 @@ func (enc *encoder) For(obj types.Object) (Path, error) { // Reject obviously non-viable cases. switch obj := obj.(type) { case *types.TypeName: - if _, ok := obj.Type().(*typeparams.TypeParam); !ok { + if _, ok := obj.Type().(*types.TypeParam); !ok { // With the exception of type parameters, only package-level type names // have a path. return "", fmt.Errorf("no path for %v", obj) @@ -260,15 +264,14 @@ func (enc *encoder) For(obj types.Object) (Path, error) { // the best paths because non-types may // refer to types, but not the reverse. empty := make([]byte, 0, 48) // initial space - names := enc.scopeNames(scope) - for _, name := range names { - o := scope.Lookup(name) + objs := enc.scopeObjects(scope) + for _, o := range objs { tname, ok := o.(*types.TypeName) if !ok { continue // handle non-types in second pass } - path := append(empty, name...) + path := append(empty, o.Name()...) path = append(path, opType) T := o.Type() @@ -280,7 +283,7 @@ func (enc *encoder) For(obj types.Object) (Path, error) { } } else { if named, _ := T.(*types.Named); named != nil { - if r := findTypeParam(obj, typeparams.ForNamed(named), path, nil); r != nil { + if r := findTypeParam(obj, named.TypeParams(), path, nil); r != nil { // generic named type return Path(r), nil } @@ -294,9 +297,8 @@ func (enc *encoder) For(obj types.Object) (Path, error) { // Then inspect everything else: // non-types, and declared methods of defined types. - for _, name := range names { - o := scope.Lookup(name) - path := append(empty, name...) + for _, o := range objs { + path := append(empty, o.Name()...) if _, ok := o.(*types.TypeName); !ok { if o.Exported() { // exported non-type (const, var, func) @@ -310,10 +312,12 @@ func (enc *encoder) For(obj types.Object) (Path, error) { // Inspect declared methods of defined types. if T, ok := o.Type().(*types.Named); ok { path = append(path, opType) - // Note that method index here is always with respect - // to canonical ordering of methods, regardless of how - // they appear in the underlying type. - for i, m := range enc.namedMethods(T) { + // The method index here is always with respect + // to the underlying go/types data structures, + // which ultimately derives from source order + // and must be preserved by export data. + for i := 0; i < T.NumMethods(); i++ { + m := T.Method(i) path2 := appendOpArg(path, opMethod, i) if m == obj { return Path(path2), nil // found declared method @@ -341,7 +345,7 @@ func appendOpArg(path []byte, op byte, arg int) []byte { // This function is just an optimization that avoids the general scope walking // approach. You are expected to fall back to the general approach if this // function fails. -func (enc *encoder) concreteMethod(meth *types.Func) (Path, bool) { +func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) { // Concrete methods can only be declared on package-scoped named types. For // that reason we can skip the expensive walk over the package scope: the // path will always be package -> named type -> method. We can trivially get @@ -414,14 +418,24 @@ func (enc *encoder) concreteMethod(meth *types.Func) (Path, bool) { path := make([]byte, 0, len(name)+8) path = append(path, name...) path = append(path, opType) - for i, m := range enc.namedMethods(named) { - if m == meth { + + // Method indices are w.r.t. the go/types data structures, + // ultimately deriving from source order, + // which is preserved by export data. + for i := 0; i < named.NumMethods(); i++ { + if named.Method(i) == meth { path = appendOpArg(path, opMethod, i) return Path(path), true } } - panic(fmt.Sprintf("couldn't find method %s on type %s", meth, named)) + // Due to golang/go#59944, go/types fails to associate the receiver with + // certain methods on cgo types. + // + // TODO(rfindley): replace this panic once golang/go#59944 is fixed in all Go + // versions gopls supports. + return "", false + // panic(fmt.Sprintf("couldn't find method %s on type %s; methods: %#v", meth, named, enc.namedMethods(named))) } // find finds obj within type T, returning the path to it, or nil if not found. @@ -448,7 +462,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] } return find(obj, T.Elem(), append(path, opElem), seen) case *types.Signature: - if r := findTypeParam(obj, typeparams.ForSignature(T), path, seen); r != nil { + if r := findTypeParam(obj, T.TypeParams(), path, seen); r != nil { return r } if r := find(obj, T.Params(), append(path, opParams), seen); r != nil { @@ -491,7 +505,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] } } return nil - case *typeparams.TypeParam: + case *types.TypeParam: name := T.Obj() if name == obj { return append(path, opObj) @@ -511,7 +525,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName] panic(T) } -func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte { +func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte { for i := 0; i < list.Len(); i++ { tparam := list.At(i) path2 := appendOpArg(path, opTypeParam, i) @@ -524,11 +538,11 @@ func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte // Object returns the object denoted by path p within the package pkg. func Object(pkg *types.Package, p Path) (types.Object, error) { - if p == "" { + pathstr := string(p) + if pathstr == "" { return nil, fmt.Errorf("empty path") } - pathstr := string(p) var pkgobj, suffix string if dot := strings.IndexByte(pathstr, opType); dot < 0 { pkgobj = pathstr @@ -548,7 +562,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { } // abstraction of *types.{Named,Signature} type hasTypeParams interface { - TypeParams() *typeparams.TypeParamList + TypeParams() *types.TypeParamList } // abstraction of *types.{Named,TypeParam} type hasObj interface { @@ -650,7 +664,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { t = tparams.At(index) case opConstraint: - tparam, ok := t.(*typeparams.TypeParam) + tparam, ok := t.(*types.TypeParam) if !ok { return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t) } @@ -687,11 +701,10 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { obj = t.Method(index) // Id-ordered case *types.Named: - methods := namedMethods(t) // (unmemoized) - if index >= len(methods) { - return nil, fmt.Errorf("method index %d out of range [0-%d)", index, len(methods)) + if index >= t.NumMethods() { + return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods()) } - obj = methods[index] // Id-ordered + obj = t.Method(index) default: return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t) @@ -718,45 +731,22 @@ func Object(pkg *types.Package, p Path) (types.Object, error) { return obj, nil // success } -// namedMethods returns the methods of a Named type in ascending Id order. -func namedMethods(named *types.Named) []*types.Func { - methods := make([]*types.Func, named.NumMethods()) - for i := range methods { - methods[i] = named.Method(i) - } - sort.Slice(methods, func(i, j int) bool { - return methods[i].Id() < methods[j].Id() - }) - return methods -} - -// scopeNames is a memoization of scope.Names. Callers must not modify the result. -func (enc *encoder) scopeNames(scope *types.Scope) []string { - m := enc.scopeNamesMemo +// scopeObjects is a memoization of scope objects. +// Callers must not modify the result. +func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object { + m := enc.scopeMemo if m == nil { - m = make(map[*types.Scope][]string) - enc.scopeNamesMemo = m + m = make(map[*types.Scope][]types.Object) + enc.scopeMemo = m } - names, ok := m[scope] + objs, ok := m[scope] if !ok { - names = scope.Names() // allocates and sorts - m[scope] = names - } - return names -} - -// namedMethods is a memoization of the namedMethods function. Callers must not modify the result. -func (enc *encoder) namedMethods(named *types.Named) []*types.Func { - m := enc.namedMethodsMemo - if m == nil { - m = make(map[*types.Named][]*types.Func) - enc.namedMethodsMemo = m - } - methods, ok := m[named] - if !ok { - methods = namedMethods(named) // allocates and sorts - m[named] = methods + names := scope.Names() // allocates and sorts + objs = make([]types.Object, len(names)) + for i, name := range names { + objs[i] = scope.Lookup(name) + } + m[scope] = objs } - return methods - + return objs } diff --git a/vendor/golang.org/x/tools/go/types/typeutil/callee.go b/vendor/golang.org/x/tools/go/types/typeutil/callee.go index 90b3ab0e2..90dc541ad 100644 --- a/vendor/golang.org/x/tools/go/types/typeutil/callee.go +++ b/vendor/golang.org/x/tools/go/types/typeutil/callee.go @@ -22,7 +22,7 @@ func Callee(info *types.Info, call *ast.CallExpr) types.Object { // Look through type instantiation if necessary. isInstance := false switch fun.(type) { - case *ast.IndexExpr, *typeparams.IndexListExpr: + case *ast.IndexExpr, *ast.IndexListExpr: // When extracting the callee from an *IndexExpr, we need to check that // it is a *types.Func and not a *types.Var. // Example: Don't match a slice m within the expression `m[0]()`. diff --git a/vendor/golang.org/x/tools/go/types/typeutil/map.go b/vendor/golang.org/x/tools/go/types/typeutil/map.go index 7bd2fdb38..544246dac 100644 --- a/vendor/golang.org/x/tools/go/types/typeutil/map.go +++ b/vendor/golang.org/x/tools/go/types/typeutil/map.go @@ -219,7 +219,7 @@ type Hasher struct { // generic types or functions, and instantiated signatures do not have type // parameter lists, we should never encounter a second non-empty type // parameter list when hashing a generic signature. - sigTParams *typeparams.TypeParamList + sigTParams *types.TypeParamList } // MakeHasher returns a new Hasher instance. @@ -297,7 +297,7 @@ func (h Hasher) hashFor(t types.Type) uint32 { // We should never encounter a generic signature while hashing another // generic signature, but defensively set sigTParams only if h.mask is // unset. - tparams := typeparams.ForSignature(t) + tparams := t.TypeParams() if h.sigTParams == nil && tparams.Len() != 0 { h = Hasher{ // There may be something more efficient than discarding the existing @@ -318,7 +318,7 @@ func (h Hasher) hashFor(t types.Type) uint32 { return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) - case *typeparams.Union: + case *types.Union: return h.hashUnion(t) case *types.Interface: @@ -354,14 +354,14 @@ func (h Hasher) hashFor(t types.Type) uint32 { case *types.Named: hash := h.hashPtr(t.Obj()) - targs := typeparams.NamedTypeArgs(t) + targs := t.TypeArgs() for i := 0; i < targs.Len(); i++ { targ := targs.At(i) hash += 2 * h.Hash(targ) } return hash - case *typeparams.TypeParam: + case *types.TypeParam: return h.hashTypeParam(t) case *types.Tuple: @@ -381,7 +381,7 @@ func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { return hash } -func (h Hasher) hashUnion(t *typeparams.Union) uint32 { +func (h Hasher) hashUnion(t *types.Union) uint32 { // Hash type restrictions. terms, err := typeparams.UnionTermSet(t) // if err != nil t has invalid type restrictions. Fall back on a non-zero @@ -392,7 +392,7 @@ func (h Hasher) hashUnion(t *typeparams.Union) uint32 { return h.hashTermSet(terms) } -func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { +func (h Hasher) hashTermSet(terms []*types.Term) uint32 { hash := 9157 + 2*uint32(len(terms)) for _, term := range terms { // term order is not significant. @@ -416,7 +416,7 @@ func (h Hasher) hashTermSet(terms []*typeparams.Term) uint32 { // are not identical. // // Otherwise the hash of t depends only on t's pointer identity. -func (h Hasher) hashTypeParam(t *typeparams.TypeParam) uint32 { +func (h Hasher) hashTypeParam(t *types.TypeParam) uint32 { if h.sigTParams != nil { i := t.Index() if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) { @@ -489,7 +489,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 { case *types.Pointer: return 4393139 - case *typeparams.Union: + case *types.Union: return 562448657 case *types.Interface: @@ -504,7 +504,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 { case *types.Named: return h.hashPtr(t.Obj()) - case *typeparams.TypeParam: + case *types.TypeParam: return h.hashPtr(t.Obj()) } panic(fmt.Sprintf("shallowHash: %T: %v", t, t)) diff --git a/vendor/golang.org/x/tools/imports/forward.go b/vendor/golang.org/x/tools/imports/forward.go index d2547c743..cb6db8893 100644 --- a/vendor/golang.org/x/tools/imports/forward.go +++ b/vendor/golang.org/x/tools/imports/forward.go @@ -7,8 +7,8 @@ package imports // import "golang.org/x/tools/imports" import ( - "io/ioutil" "log" + "os" "golang.org/x/tools/internal/gocommand" intimp "golang.org/x/tools/internal/imports" @@ -44,7 +44,7 @@ var LocalPrefix string func Process(filename string, src []byte, opt *Options) ([]byte, error) { var err error if src == nil { - src, err = ioutil.ReadFile(filename) + src, err = os.ReadFile(filename) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go new file mode 100644 index 000000000..2b2916804 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go @@ -0,0 +1,386 @@ +// Copyright 2020 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 analysisinternal provides gopls' internal analyses with a +// number of helper functions that operate on typed syntax trees. +package analysisinternal + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "go/types" + "strconv" +) + +func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos { + // Get the end position for the type error. + offset, end := fset.PositionFor(start, false).Offset, start + if offset >= len(src) { + return end + } + if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 { + end = start + token.Pos(width) + } + return end +} + +func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { + under := typ + if n, ok := typ.(*types.Named); ok { + under = n.Underlying() + } + switch u := under.(type) { + case *types.Basic: + switch { + case u.Info()&types.IsNumeric != 0: + return &ast.BasicLit{Kind: token.INT, Value: "0"} + case u.Info()&types.IsBoolean != 0: + return &ast.Ident{Name: "false"} + case u.Info()&types.IsString != 0: + return &ast.BasicLit{Kind: token.STRING, Value: `""`} + default: + panic(fmt.Sprintf("unknown basic type %v", u)) + } + case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array: + return ast.NewIdent("nil") + case *types.Struct: + texpr := TypeExpr(f, pkg, typ) // typ because we want the name here. + if texpr == nil { + return nil + } + return &ast.CompositeLit{ + Type: texpr, + } + } + return nil +} + +// IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of +// analysisinternal.ZeroValue) +func IsZeroValue(expr ast.Expr) bool { + switch e := expr.(type) { + case *ast.BasicLit: + return e.Value == "0" || e.Value == `""` + case *ast.Ident: + return e.Name == "nil" || e.Name == "false" + default: + return false + } +} + +// TypeExpr returns syntax for the specified type. References to +// named types from packages other than pkg are qualified by an appropriate +// package name, as defined by the import environment of file. +func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { + switch t := typ.(type) { + case *types.Basic: + switch t.Kind() { + case types.UnsafePointer: + return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")} + default: + return ast.NewIdent(t.Name()) + } + case *types.Pointer: + x := TypeExpr(f, pkg, t.Elem()) + if x == nil { + return nil + } + return &ast.UnaryExpr{ + Op: token.MUL, + X: x, + } + case *types.Array: + elt := TypeExpr(f, pkg, t.Elem()) + if elt == nil { + return nil + } + return &ast.ArrayType{ + Len: &ast.BasicLit{ + Kind: token.INT, + Value: fmt.Sprintf("%d", t.Len()), + }, + Elt: elt, + } + case *types.Slice: + elt := TypeExpr(f, pkg, t.Elem()) + if elt == nil { + return nil + } + return &ast.ArrayType{ + Elt: elt, + } + case *types.Map: + key := TypeExpr(f, pkg, t.Key()) + value := TypeExpr(f, pkg, t.Elem()) + if key == nil || value == nil { + return nil + } + return &ast.MapType{ + Key: key, + Value: value, + } + case *types.Chan: + dir := ast.ChanDir(t.Dir()) + if t.Dir() == types.SendRecv { + dir = ast.SEND | ast.RECV + } + value := TypeExpr(f, pkg, t.Elem()) + if value == nil { + return nil + } + return &ast.ChanType{ + Dir: dir, + Value: value, + } + case *types.Signature: + var params []*ast.Field + for i := 0; i < t.Params().Len(); i++ { + p := TypeExpr(f, pkg, t.Params().At(i).Type()) + if p == nil { + return nil + } + params = append(params, &ast.Field{ + Type: p, + Names: []*ast.Ident{ + { + Name: t.Params().At(i).Name(), + }, + }, + }) + } + var returns []*ast.Field + for i := 0; i < t.Results().Len(); i++ { + r := TypeExpr(f, pkg, t.Results().At(i).Type()) + if r == nil { + return nil + } + returns = append(returns, &ast.Field{ + Type: r, + }) + } + return &ast.FuncType{ + Params: &ast.FieldList{ + List: params, + }, + Results: &ast.FieldList{ + List: returns, + }, + } + case *types.Named: + if t.Obj().Pkg() == nil { + return ast.NewIdent(t.Obj().Name()) + } + if t.Obj().Pkg() == pkg { + return ast.NewIdent(t.Obj().Name()) + } + pkgName := t.Obj().Pkg().Name() + + // If the file already imports the package under another name, use that. + for _, cand := range f.Imports { + if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() { + if cand.Name != nil && cand.Name.Name != "" { + pkgName = cand.Name.Name + } + } + } + if pkgName == "." { + return ast.NewIdent(t.Obj().Name()) + } + return &ast.SelectorExpr{ + X: ast.NewIdent(pkgName), + Sel: ast.NewIdent(t.Obj().Name()), + } + case *types.Struct: + return ast.NewIdent(t.String()) + case *types.Interface: + return ast.NewIdent(t.String()) + default: + return nil + } +} + +// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable. +// Some examples: +// +// Basic Example: +// z := 1 +// y := z + x +// If x is undeclared, then this function would return `y := z + x`, so that we +// can insert `x := ` on the line before `y := z + x`. +// +// If stmt example: +// if z == 1 { +// } else if z == y {} +// If y is undeclared, then this function would return `if z == 1 {`, because we cannot +// insert a statement between an if and an else if statement. As a result, we need to find +// the top of the if chain to insert `y := ` before. +func StmtToInsertVarBefore(path []ast.Node) ast.Stmt { + enclosingIndex := -1 + for i, p := range path { + if _, ok := p.(ast.Stmt); ok { + enclosingIndex = i + break + } + } + if enclosingIndex == -1 { + return nil + } + enclosingStmt := path[enclosingIndex] + switch enclosingStmt.(type) { + case *ast.IfStmt: + // The enclosingStmt is inside of the if declaration, + // We need to check if we are in an else-if stmt and + // get the base if statement. + return baseIfStmt(path, enclosingIndex) + case *ast.CaseClause: + // Get the enclosing switch stmt if the enclosingStmt is + // inside of the case statement. + for i := enclosingIndex + 1; i < len(path); i++ { + if node, ok := path[i].(*ast.SwitchStmt); ok { + return node + } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok { + return node + } + } + } + if len(path) <= enclosingIndex+1 { + return enclosingStmt.(ast.Stmt) + } + // Check if the enclosing statement is inside another node. + switch expr := path[enclosingIndex+1].(type) { + case *ast.IfStmt: + // Get the base if statement. + return baseIfStmt(path, enclosingIndex+1) + case *ast.ForStmt: + if expr.Init == enclosingStmt || expr.Post == enclosingStmt { + return expr + } + } + return enclosingStmt.(ast.Stmt) +} + +// baseIfStmt walks up the if/else-if chain until we get to +// the top of the current if chain. +func baseIfStmt(path []ast.Node, index int) ast.Stmt { + stmt := path[index] + for i := index + 1; i < len(path); i++ { + if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt { + stmt = node + continue + } + break + } + return stmt.(ast.Stmt) +} + +// WalkASTWithParent walks the AST rooted at n. The semantics are +// similar to ast.Inspect except it does not call f(nil). +func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) { + var ancestors []ast.Node + ast.Inspect(n, func(n ast.Node) (recurse bool) { + if n == nil { + ancestors = ancestors[:len(ancestors)-1] + return false + } + + var parent ast.Node + if len(ancestors) > 0 { + parent = ancestors[len(ancestors)-1] + } + ancestors = append(ancestors, n) + return f(n, parent) + }) +} + +// MatchingIdents finds the names of all identifiers in 'node' that match any of the given types. +// 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within +// the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that +// is unrecognized. +func MatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]string { + + // Initialize matches to contain the variable types we are searching for. + matches := make(map[types.Type][]string) + for _, typ := range typs { + if typ == nil { + continue // TODO(adonovan): is this reachable? + } + matches[typ] = nil // create entry + } + + seen := map[types.Object]struct{}{} + ast.Inspect(node, func(n ast.Node) bool { + if n == nil { + return false + } + // Prevent circular definitions. If 'pos' is within an assignment statement, do not + // allow any identifiers in that assignment statement to be selected. Otherwise, + // we could do the following, where 'x' satisfies the type of 'f0': + // + // x := fakeStruct{f0: x} + // + if assign, ok := n.(*ast.AssignStmt); ok && pos > assign.Pos() && pos <= assign.End() { + return false + } + if n.End() > pos { + return n.Pos() <= pos + } + ident, ok := n.(*ast.Ident) + if !ok || ident.Name == "_" { + return true + } + obj := info.Defs[ident] + if obj == nil || obj.Type() == nil { + return true + } + if _, ok := obj.(*types.TypeName); ok { + return true + } + // Prevent duplicates in matches' values. + if _, ok = seen[obj]; ok { + return true + } + seen[obj] = struct{}{} + // Find the scope for the given position. Then, check whether the object + // exists within the scope. + innerScope := pkg.Scope().Innermost(pos) + if innerScope == nil { + return true + } + _, foundObj := innerScope.LookupParent(ident.Name, pos) + if foundObj != obj { + return true + } + // The object must match one of the types that we are searching for. + // TODO(adonovan): opt: use typeutil.Map? + if names, ok := matches[obj.Type()]; ok { + matches[obj.Type()] = append(names, ident.Name) + } else { + // If the object type does not exactly match + // any of the target types, greedily find the first + // target type that the object type can satisfy. + for typ := range matches { + if equivalentTypes(obj.Type(), typ) { + matches[typ] = append(matches[typ], ident.Name) + } + } + } + return true + }) + return matches +} + +func equivalentTypes(want, got types.Type) bool { + if types.Identical(want, got) { + return true + } + // Code segment to help check for untyped equality from (golang/go#32146). + if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 { + if lhs, ok := got.Underlying().(*types.Basic); ok { + return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType + } + } + return types.AssignableTo(want, got) +} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go b/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go similarity index 99% rename from vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go rename to vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go index 0e175ca06..39507723d 100644 --- a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/extractdoc.go +++ b/vendor/golang.org/x/tools/internal/analysisinternal/extractdoc.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package analysisutil +package analysisinternal import ( "fmt" diff --git a/vendor/golang.org/x/tools/internal/event/keys/util.go b/vendor/golang.org/x/tools/internal/event/keys/util.go new file mode 100644 index 000000000..c0e8e731c --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/keys/util.go @@ -0,0 +1,21 @@ +// Copyright 2023 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 keys + +import ( + "sort" + "strings" +) + +// Join returns a canonical join of the keys in S: +// a sorted comma-separated string list. +func Join[S ~[]T, T ~string](s S) string { + strs := make([]string, 0, len(s)) + for _, v := range s { + strs = append(strs, string(v)) + } + sort.Strings(strs) + return strings.Join(strs, ",") +} diff --git a/vendor/golang.org/x/tools/internal/event/tag/tag.go b/vendor/golang.org/x/tools/internal/event/tag/tag.go new file mode 100644 index 000000000..581b26c20 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/tag/tag.go @@ -0,0 +1,59 @@ +// 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 tag provides the labels used for telemetry throughout gopls. +package tag + +import ( + "golang.org/x/tools/internal/event/keys" +) + +var ( + // create the label keys we use + Method = keys.NewString("method", "") + StatusCode = keys.NewString("status.code", "") + StatusMessage = keys.NewString("status.message", "") + RPCID = keys.NewString("id", "") + RPCDirection = keys.NewString("direction", "") + File = keys.NewString("file", "") + Directory = keys.New("directory", "") + URI = keys.New("URI", "") + Package = keys.NewString("package", "") // sorted comma-separated list of Package IDs + PackagePath = keys.NewString("package_path", "") + Query = keys.New("query", "") + Snapshot = keys.NewUInt64("snapshot", "") + Operation = keys.NewString("operation", "") + + Position = keys.New("position", "") + Category = keys.NewString("category", "") + PackageCount = keys.NewInt("packages", "") + Files = keys.New("files", "") + Port = keys.NewInt("port", "") + Type = keys.New("type", "") + HoverKind = keys.NewString("hoverkind", "") + + NewServer = keys.NewString("new_server", "A new server was added") + EndServer = keys.NewString("end_server", "A server was shut down") + + ServerID = keys.NewString("server", "The server ID an event is related to") + Logfile = keys.NewString("logfile", "") + DebugAddress = keys.NewString("debug_address", "") + GoplsPath = keys.NewString("gopls_path", "") + ClientID = keys.NewString("client_id", "") + + Level = keys.NewInt("level", "The logging level") +) + +var ( + // create the stats we measure + Started = keys.NewInt64("started", "Count of started RPCs.") + ReceivedBytes = keys.NewInt64("received_bytes", "Bytes received.") //, unit.Bytes) + SentBytes = keys.NewInt64("sent_bytes", "Bytes sent.") //, unit.Bytes) + Latency = keys.NewFloat64("latency_ms", "Elapsed time in milliseconds") //, unit.Milliseconds) +) + +const ( + Inbound = "in" + Outbound = "out" +) diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go deleted file mode 100644 index 798fe599b..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package fastwalk provides a faster version of filepath.Walk for file system -// scanning tools. -package fastwalk - -import ( - "errors" - "os" - "path/filepath" - "runtime" - "sync" -) - -// ErrTraverseLink is used as a return value from WalkFuncs to indicate that the -// symlink named in the call may be traversed. -var ErrTraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory") - -// ErrSkipFiles is a used as a return value from WalkFuncs to indicate that the -// callback should not be called for any other files in the current directory. -// Child directories will still be traversed. -var ErrSkipFiles = errors.New("fastwalk: skip remaining files in directory") - -// Walk is a faster implementation of filepath.Walk. -// -// filepath.Walk's design necessarily calls os.Lstat on each file, -// even if the caller needs less info. -// Many tools need only the type of each file. -// On some platforms, this information is provided directly by the readdir -// system call, avoiding the need to stat each file individually. -// fastwalk_unix.go contains a fork of the syscall routines. -// -// See golang.org/issue/16399 -// -// Walk walks the file tree rooted at root, calling walkFn for -// each file or directory in the tree, including root. -// -// If fastWalk returns filepath.SkipDir, the directory is skipped. -// -// Unlike filepath.Walk: -// - file stat calls must be done by the user. -// The only provided metadata is the file type, which does not include -// any permission bits. -// - multiple goroutines stat the filesystem concurrently. The provided -// walkFn must be safe for concurrent use. -// - fastWalk can follow symlinks if walkFn returns the TraverseLink -// sentinel error. It is the walkFn's responsibility to prevent -// fastWalk from going into symlink cycles. -func Walk(root string, walkFn func(path string, typ os.FileMode) error) error { - // TODO(bradfitz): make numWorkers configurable? We used a - // minimum of 4 to give the kernel more info about multiple - // things we want, in hopes its I/O scheduling can take - // advantage of that. Hopefully most are in cache. Maybe 4 is - // even too low of a minimum. Profile more. - numWorkers := 4 - if n := runtime.NumCPU(); n > numWorkers { - numWorkers = n - } - - // Make sure to wait for all workers to finish, otherwise - // walkFn could still be called after returning. This Wait call - // runs after close(e.donec) below. - var wg sync.WaitGroup - defer wg.Wait() - - w := &walker{ - fn: walkFn, - enqueuec: make(chan walkItem, numWorkers), // buffered for performance - workc: make(chan walkItem, numWorkers), // buffered for performance - donec: make(chan struct{}), - - // buffered for correctness & not leaking goroutines: - resc: make(chan error, numWorkers), - } - defer close(w.donec) - - for i := 0; i < numWorkers; i++ { - wg.Add(1) - go w.doWork(&wg) - } - todo := []walkItem{{dir: root}} - out := 0 - for { - workc := w.workc - var workItem walkItem - if len(todo) == 0 { - workc = nil - } else { - workItem = todo[len(todo)-1] - } - select { - case workc <- workItem: - todo = todo[:len(todo)-1] - out++ - case it := <-w.enqueuec: - todo = append(todo, it) - case err := <-w.resc: - out-- - if err != nil { - return err - } - if out == 0 && len(todo) == 0 { - // It's safe to quit here, as long as the buffered - // enqueue channel isn't also readable, which might - // happen if the worker sends both another unit of - // work and its result before the other select was - // scheduled and both w.resc and w.enqueuec were - // readable. - select { - case it := <-w.enqueuec: - todo = append(todo, it) - default: - return nil - } - } - } - } -} - -// doWork reads directories as instructed (via workc) and runs the -// user's callback function. -func (w *walker) doWork(wg *sync.WaitGroup) { - defer wg.Done() - for { - select { - case <-w.donec: - return - case it := <-w.workc: - select { - case <-w.donec: - return - case w.resc <- w.walk(it.dir, !it.callbackDone): - } - } - } -} - -type walker struct { - fn func(path string, typ os.FileMode) error - - donec chan struct{} // closed on fastWalk's return - workc chan walkItem // to workers - enqueuec chan walkItem // from workers - resc chan error // from workers -} - -type walkItem struct { - dir string - callbackDone bool // callback already called; don't do it again -} - -func (w *walker) enqueue(it walkItem) { - select { - case w.enqueuec <- it: - case <-w.donec: - } -} - -func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { - joined := dirName + string(os.PathSeparator) + baseName - if typ == os.ModeDir { - w.enqueue(walkItem{dir: joined}) - return nil - } - - err := w.fn(joined, typ) - if typ == os.ModeSymlink { - if err == ErrTraverseLink { - // Set callbackDone so we don't call it twice for both the - // symlink-as-symlink and the symlink-as-directory later: - w.enqueue(walkItem{dir: joined, callbackDone: true}) - return nil - } - if err == filepath.SkipDir { - // Permit SkipDir on symlinks too. - return nil - } - } - return err -} - -func (w *walker) walk(root string, runUserCallback bool) error { - if runUserCallback { - err := w.fn(root, os.ModeDir) - if err == filepath.SkipDir { - return nil - } - if err != nil { - return err - } - } - - return readDir(root, w.onDirEnt) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go deleted file mode 100644 index 0ca55e0d5..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && cgo -// +build darwin,cgo - -package fastwalk - -/* -#include - -// fastwalk_readdir_r wraps readdir_r so that we don't have to pass a dirent** -// result pointer which triggers CGO's "Go pointer to Go pointer" check unless -// we allocat the result dirent* with malloc. -// -// fastwalk_readdir_r returns 0 on success, -1 upon reaching the end of the -// directory, or a positive error number to indicate failure. -static int fastwalk_readdir_r(DIR *fd, struct dirent *entry) { - struct dirent *result; - int ret = readdir_r(fd, entry, &result); - if (ret == 0 && result == NULL) { - ret = -1; // EOF - } - return ret; -} -*/ -import "C" - -import ( - "os" - "syscall" - "unsafe" -) - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := openDir(dirName) - if err != nil { - return &os.PathError{Op: "opendir", Path: dirName, Err: err} - } - defer C.closedir(fd) - - skipFiles := false - var dirent syscall.Dirent - for { - ret := int(C.fastwalk_readdir_r(fd, (*C.struct_dirent)(unsafe.Pointer(&dirent)))) - if ret != 0 { - if ret == -1 { - break // EOF - } - if ret == int(syscall.EINTR) { - continue - } - return &os.PathError{Op: "readdir", Path: dirName, Err: syscall.Errno(ret)} - } - if dirent.Ino == 0 { - continue - } - typ := dtToType(dirent.Type) - if skipFiles && typ.IsRegular() { - continue - } - name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:] - name = name[:dirent.Namlen] - for i, c := range name { - if c == 0 { - name = name[:i] - break - } - } - // Check for useless names before allocating a string. - if string(name) == "." || string(name) == ".." { - continue - } - if err := fn(dirName, string(name), typ); err != nil { - if err != ErrSkipFiles { - return err - } - skipFiles = true - } - } - - return nil -} - -func dtToType(typ uint8) os.FileMode { - switch typ { - case syscall.DT_BLK: - return os.ModeDevice - case syscall.DT_CHR: - return os.ModeDevice | os.ModeCharDevice - case syscall.DT_DIR: - return os.ModeDir - case syscall.DT_FIFO: - return os.ModeNamedPipe - case syscall.DT_LNK: - return os.ModeSymlink - case syscall.DT_REG: - return 0 - case syscall.DT_SOCK: - return os.ModeSocket - } - return ^os.FileMode(0) -} - -// openDir wraps opendir(3) and handles any EINTR errors. The returned *DIR -// needs to be closed with closedir(3). -func openDir(path string) (*C.DIR, error) { - name, err := syscall.BytePtrFromString(path) - if err != nil { - return nil, err - } - for { - fd, err := C.opendir((*C.char)(unsafe.Pointer(name))) - if err != syscall.EINTR { - return fd, err - } - } -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go deleted file mode 100644 index d58595dbd..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build freebsd || openbsd || netbsd -// +build freebsd openbsd netbsd - -package fastwalk - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Fileno) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go deleted file mode 100644 index d3922890b..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (linux || (darwin && !cgo)) && !appengine -// +build linux darwin,!cgo -// +build !appengine - -package fastwalk - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return dirent.Ino -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go deleted file mode 100644 index 38a4db6af..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (darwin && !cgo) || freebsd || openbsd || netbsd -// +build darwin,!cgo freebsd openbsd netbsd - -package fastwalk - -import "syscall" - -func direntNamlen(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Namlen) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go deleted file mode 100644 index c82e57df8..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && !appengine -// +build linux,!appengine - -package fastwalk - -import ( - "bytes" - "syscall" - "unsafe" -) - -func direntNamlen(dirent *syscall.Dirent) uint64 { - const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - const nameBufLen = uint16(len(nameBuf)) - limit := dirent.Reclen - fixedHdr - if limit > nameBufLen { - limit = nameBufLen - } - nameLen := bytes.IndexByte(nameBuf[:limit], 0) - if nameLen < 0 { - panic("failed to find terminating 0 byte in dirent") - } - return uint64(nameLen) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go deleted file mode 100644 index 085d31160..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build appengine || (!linux && !darwin && !freebsd && !openbsd && !netbsd) -// +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd - -package fastwalk - -import ( - "io/ioutil" - "os" -) - -// readDir calls fn for each directory entry in dirName. -// It does not descend into directories or follow symlinks. -// If fn returns a non-nil error, readDir returns with that error -// immediately. -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fis, err := ioutil.ReadDir(dirName) - if err != nil { - return err - } - skipFiles := false - for _, fi := range fis { - if fi.Mode().IsRegular() && skipFiles { - continue - } - if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue - } - return err - } - } - return nil -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go deleted file mode 100644 index f12f1a734..000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (linux || freebsd || openbsd || netbsd || (darwin && !cgo)) && !appengine -// +build linux freebsd openbsd netbsd darwin,!cgo -// +build !appengine - -package fastwalk - -import ( - "fmt" - "os" - "syscall" - "unsafe" -) - -const blockSize = 8 << 10 - -// unknownFileMode is a sentinel (and bogus) os.FileMode -// value used to represent a syscall.DT_UNKNOWN Dirent.Type. -const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := open(dirName, 0, 0) - if err != nil { - return &os.PathError{Op: "open", Path: dirName, Err: err} - } - defer syscall.Close(fd) - - // The buffer must be at least a block long. - buf := make([]byte, blockSize) // stack-allocated; doesn't escape - bufp := 0 // starting read position in buf - nbuf := 0 // end valid data in buf - skipFiles := false - for { - if bufp >= nbuf { - bufp = 0 - nbuf, err = readDirent(fd, buf) - if err != nil { - return os.NewSyscallError("readdirent", err) - } - if nbuf <= 0 { - return nil - } - } - consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) - bufp += consumed - if name == "" || name == "." || name == ".." { - continue - } - // Fallback for filesystems (like old XFS) that don't - // support Dirent.Type and have DT_UNKNOWN (0) there - // instead. - if typ == unknownFileMode { - fi, err := os.Lstat(dirName + "/" + name) - if err != nil { - // It got deleted in the meantime. - if os.IsNotExist(err) { - continue - } - return err - } - typ = fi.Mode() & os.ModeType - } - if skipFiles && typ.IsRegular() { - continue - } - if err := fn(dirName, name, typ); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue - } - return err - } - } -} - -func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { - // golang.org/issue/37269 - dirent := &syscall.Dirent{} - copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(dirent))[:], buf) - if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { - panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) - } - if len(buf) < int(dirent.Reclen) { - panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) - } - consumed = int(dirent.Reclen) - if direntInode(dirent) == 0 { // File absent in directory. - return - } - switch dirent.Type { - case syscall.DT_REG: - typ = 0 - case syscall.DT_DIR: - typ = os.ModeDir - case syscall.DT_LNK: - typ = os.ModeSymlink - case syscall.DT_BLK: - typ = os.ModeDevice - case syscall.DT_FIFO: - typ = os.ModeNamedPipe - case syscall.DT_SOCK: - typ = os.ModeSocket - case syscall.DT_UNKNOWN: - typ = unknownFileMode - default: - // Skip weird things. - // It's probably a DT_WHT (http://lwn.net/Articles/325369/) - // or something. Revisit if/when this package is moved outside - // of goimports. goimports only cares about regular files, - // symlinks, and directories. - return - } - - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - nameLen := direntNamlen(dirent) - - // Special cases for common things: - if nameLen == 1 && nameBuf[0] == '.' { - name = "." - } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { - name = ".." - } else { - name = string(nameBuf[:nameLen]) - } - return -} - -// According to https://golang.org/doc/go1.14#runtime -// A consequence of the implementation of preemption is that on Unix systems, including Linux and macOS -// systems, programs built with Go 1.14 will receive more signals than programs built with earlier releases. -// -// This causes syscall.Open and syscall.ReadDirent sometimes fail with EINTR errors. -// We need to retry in this case. -func open(path string, mode int, perm uint32) (fd int, err error) { - for { - fd, err := syscall.Open(path, mode, perm) - if err != syscall.EINTR { - return fd, err - } - } -} - -func readDirent(fd int, buf []byte) (n int, err error) { - for { - nbuf, err := syscall.ReadDirent(fd, buf) - if err != syscall.EINTR { - return nbuf, err - } - } -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/bexport.go b/vendor/golang.org/x/tools/internal/gcimporter/bexport.go deleted file mode 100644 index 30582ed6d..000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/bexport.go +++ /dev/null @@ -1,852 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Binary package export. -// This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go; -// see that file for specification of the format. - -package gcimporter - -import ( - "bytes" - "encoding/binary" - "fmt" - "go/constant" - "go/token" - "go/types" - "math" - "math/big" - "sort" - "strings" -) - -// If debugFormat is set, each integer and string value is preceded by a marker -// and position information in the encoding. This mechanism permits an importer -// to recognize immediately when it is out of sync. The importer recognizes this -// mode automatically (i.e., it can import export data produced with debugging -// support even if debugFormat is not set at the time of import). This mode will -// lead to massively larger export data (by a factor of 2 to 3) and should only -// be enabled during development and debugging. -// -// NOTE: This flag is the first flag to enable if importing dies because of -// (suspected) format errors, and whenever a change is made to the format. -const debugFormat = false // default: false - -// Current export format version. Increase with each format change. -// -// Note: The latest binary (non-indexed) export format is at version 6. -// This exporter is still at level 4, but it doesn't matter since -// the binary importer can handle older versions just fine. -// -// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE -// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMENTED HERE -// 4: type name objects support type aliases, uses aliasTag -// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used) -// 2: removed unused bool in ODCL export (compiler only) -// 1: header format change (more regular), export package for _ struct fields -// 0: Go1.7 encoding -const exportVersion = 4 - -// trackAllTypes enables cycle tracking for all types, not just named -// types. The existing compiler invariants assume that unnamed types -// that are not completely set up are not used, or else there are spurious -// errors. -// If disabled, only named types are tracked, possibly leading to slightly -// less efficient encoding in rare cases. It also prevents the export of -// some corner-case type declarations (but those are not handled correctly -// with with the textual export format either). -// TODO(gri) enable and remove once issues caused by it are fixed -const trackAllTypes = false - -type exporter struct { - fset *token.FileSet - out bytes.Buffer - - // object -> index maps, indexed in order of serialization - strIndex map[string]int - pkgIndex map[*types.Package]int - typIndex map[types.Type]int - - // position encoding - posInfoFormat bool - prevFile string - prevLine int - - // debugging support - written int // bytes written - indent int // for trace -} - -// internalError represents an error generated inside this package. -type internalError string - -func (e internalError) Error() string { return "gcimporter: " + string(e) } - -func internalErrorf(format string, args ...interface{}) error { - return internalError(fmt.Sprintf(format, args...)) -} - -// BExportData returns binary export data for pkg. -// If no file set is provided, position info will be missing. -func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) { - if !debug { - defer func() { - if e := recover(); e != nil { - if ierr, ok := e.(internalError); ok { - err = ierr - return - } - // Not an internal error; panic again. - panic(e) - } - }() - } - - p := exporter{ - fset: fset, - strIndex: map[string]int{"": 0}, // empty string is mapped to 0 - pkgIndex: make(map[*types.Package]int), - typIndex: make(map[types.Type]int), - posInfoFormat: true, // TODO(gri) might become a flag, eventually - } - - // write version info - // The version string must start with "version %d" where %d is the version - // number. Additional debugging information may follow after a blank; that - // text is ignored by the importer. - p.rawStringln(fmt.Sprintf("version %d", exportVersion)) - var debug string - if debugFormat { - debug = "debug" - } - p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly - p.bool(trackAllTypes) - p.bool(p.posInfoFormat) - - // --- generic export data --- - - // populate type map with predeclared "known" types - for index, typ := range predeclared() { - p.typIndex[typ] = index - } - if len(p.typIndex) != len(predeclared()) { - return nil, internalError("duplicate entries in type map?") - } - - // write package data - p.pkg(pkg, true) - if trace { - p.tracef("\n") - } - - // write objects - objcount := 0 - scope := pkg.Scope() - for _, name := range scope.Names() { - if !token.IsExported(name) { - continue - } - if trace { - p.tracef("\n") - } - p.obj(scope.Lookup(name)) - objcount++ - } - - // indicate end of list - if trace { - p.tracef("\n") - } - p.tag(endTag) - - // for self-verification only (redundant) - p.int(objcount) - - if trace { - p.tracef("\n") - } - - // --- end of export data --- - - return p.out.Bytes(), nil -} - -func (p *exporter) pkg(pkg *types.Package, emptypath bool) { - if pkg == nil { - panic(internalError("unexpected nil pkg")) - } - - // if we saw the package before, write its index (>= 0) - if i, ok := p.pkgIndex[pkg]; ok { - p.index('P', i) - return - } - - // otherwise, remember the package, write the package tag (< 0) and package data - if trace { - p.tracef("P%d = { ", len(p.pkgIndex)) - defer p.tracef("} ") - } - p.pkgIndex[pkg] = len(p.pkgIndex) - - p.tag(packageTag) - p.string(pkg.Name()) - if emptypath { - p.string("") - } else { - p.string(pkg.Path()) - } -} - -func (p *exporter) obj(obj types.Object) { - switch obj := obj.(type) { - case *types.Const: - p.tag(constTag) - p.pos(obj) - p.qualifiedName(obj) - p.typ(obj.Type()) - p.value(obj.Val()) - - case *types.TypeName: - if obj.IsAlias() { - p.tag(aliasTag) - p.pos(obj) - p.qualifiedName(obj) - } else { - p.tag(typeTag) - } - p.typ(obj.Type()) - - case *types.Var: - p.tag(varTag) - p.pos(obj) - p.qualifiedName(obj) - p.typ(obj.Type()) - - case *types.Func: - p.tag(funcTag) - p.pos(obj) - p.qualifiedName(obj) - sig := obj.Type().(*types.Signature) - p.paramList(sig.Params(), sig.Variadic()) - p.paramList(sig.Results(), false) - - default: - panic(internalErrorf("unexpected object %v (%T)", obj, obj)) - } -} - -func (p *exporter) pos(obj types.Object) { - if !p.posInfoFormat { - return - } - - file, line := p.fileLine(obj) - if file == p.prevFile { - // common case: write line delta - // delta == 0 means different file or no line change - delta := line - p.prevLine - p.int(delta) - if delta == 0 { - p.int(-1) // -1 means no file change - } - } else { - // different file - p.int(0) - // Encode filename as length of common prefix with previous - // filename, followed by (possibly empty) suffix. Filenames - // frequently share path prefixes, so this can save a lot - // of space and make export data size less dependent on file - // path length. The suffix is unlikely to be empty because - // file names tend to end in ".go". - n := commonPrefixLen(p.prevFile, file) - p.int(n) // n >= 0 - p.string(file[n:]) // write suffix only - p.prevFile = file - p.int(line) - } - p.prevLine = line -} - -func (p *exporter) fileLine(obj types.Object) (file string, line int) { - if p.fset != nil { - pos := p.fset.Position(obj.Pos()) - file = pos.Filename - line = pos.Line - } - return -} - -func commonPrefixLen(a, b string) int { - if len(a) > len(b) { - a, b = b, a - } - // len(a) <= len(b) - i := 0 - for i < len(a) && a[i] == b[i] { - i++ - } - return i -} - -func (p *exporter) qualifiedName(obj types.Object) { - p.string(obj.Name()) - p.pkg(obj.Pkg(), false) -} - -func (p *exporter) typ(t types.Type) { - if t == nil { - panic(internalError("nil type")) - } - - // Possible optimization: Anonymous pointer types *T where - // T is a named type are common. We could canonicalize all - // such types *T to a single type PT = *T. This would lead - // to at most one *T entry in typIndex, and all future *T's - // would be encoded as the respective index directly. Would - // save 1 byte (pointerTag) per *T and reduce the typIndex - // size (at the cost of a canonicalization map). We can do - // this later, without encoding format change. - - // if we saw the type before, write its index (>= 0) - if i, ok := p.typIndex[t]; ok { - p.index('T', i) - return - } - - // otherwise, remember the type, write the type tag (< 0) and type data - if trackAllTypes { - if trace { - p.tracef("T%d = {>\n", len(p.typIndex)) - defer p.tracef("<\n} ") - } - p.typIndex[t] = len(p.typIndex) - } - - switch t := t.(type) { - case *types.Named: - if !trackAllTypes { - // if we don't track all types, track named types now - p.typIndex[t] = len(p.typIndex) - } - - p.tag(namedTag) - p.pos(t.Obj()) - p.qualifiedName(t.Obj()) - p.typ(t.Underlying()) - if !types.IsInterface(t) { - p.assocMethods(t) - } - - case *types.Array: - p.tag(arrayTag) - p.int64(t.Len()) - p.typ(t.Elem()) - - case *types.Slice: - p.tag(sliceTag) - p.typ(t.Elem()) - - case *dddSlice: - p.tag(dddTag) - p.typ(t.elem) - - case *types.Struct: - p.tag(structTag) - p.fieldList(t) - - case *types.Pointer: - p.tag(pointerTag) - p.typ(t.Elem()) - - case *types.Signature: - p.tag(signatureTag) - p.paramList(t.Params(), t.Variadic()) - p.paramList(t.Results(), false) - - case *types.Interface: - p.tag(interfaceTag) - p.iface(t) - - case *types.Map: - p.tag(mapTag) - p.typ(t.Key()) - p.typ(t.Elem()) - - case *types.Chan: - p.tag(chanTag) - p.int(int(3 - t.Dir())) // hack - p.typ(t.Elem()) - - default: - panic(internalErrorf("unexpected type %T: %s", t, t)) - } -} - -func (p *exporter) assocMethods(named *types.Named) { - // Sort methods (for determinism). - var methods []*types.Func - for i := 0; i < named.NumMethods(); i++ { - methods = append(methods, named.Method(i)) - } - sort.Sort(methodsByName(methods)) - - p.int(len(methods)) - - if trace && methods != nil { - p.tracef("associated methods {>\n") - } - - for i, m := range methods { - if trace && i > 0 { - p.tracef("\n") - } - - p.pos(m) - name := m.Name() - p.string(name) - if !exported(name) { - p.pkg(m.Pkg(), false) - } - - sig := m.Type().(*types.Signature) - p.paramList(types.NewTuple(sig.Recv()), false) - p.paramList(sig.Params(), sig.Variadic()) - p.paramList(sig.Results(), false) - p.int(0) // dummy value for go:nointerface pragma - ignored by importer - } - - if trace && methods != nil { - p.tracef("<\n} ") - } -} - -type methodsByName []*types.Func - -func (x methodsByName) Len() int { return len(x) } -func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() } - -func (p *exporter) fieldList(t *types.Struct) { - if trace && t.NumFields() > 0 { - p.tracef("fields {>\n") - defer p.tracef("<\n} ") - } - - p.int(t.NumFields()) - for i := 0; i < t.NumFields(); i++ { - if trace && i > 0 { - p.tracef("\n") - } - p.field(t.Field(i)) - p.string(t.Tag(i)) - } -} - -func (p *exporter) field(f *types.Var) { - if !f.IsField() { - panic(internalError("field expected")) - } - - p.pos(f) - p.fieldName(f) - p.typ(f.Type()) -} - -func (p *exporter) iface(t *types.Interface) { - // TODO(gri): enable importer to load embedded interfaces, - // then emit Embeddeds and ExplicitMethods separately here. - p.int(0) - - n := t.NumMethods() - if trace && n > 0 { - p.tracef("methods {>\n") - defer p.tracef("<\n} ") - } - p.int(n) - for i := 0; i < n; i++ { - if trace && i > 0 { - p.tracef("\n") - } - p.method(t.Method(i)) - } -} - -func (p *exporter) method(m *types.Func) { - sig := m.Type().(*types.Signature) - if sig.Recv() == nil { - panic(internalError("method expected")) - } - - p.pos(m) - p.string(m.Name()) - if m.Name() != "_" && !token.IsExported(m.Name()) { - p.pkg(m.Pkg(), false) - } - - // interface method; no need to encode receiver. - p.paramList(sig.Params(), sig.Variadic()) - p.paramList(sig.Results(), false) -} - -func (p *exporter) fieldName(f *types.Var) { - name := f.Name() - - if f.Anonymous() { - // anonymous field - we distinguish between 3 cases: - // 1) field name matches base type name and is exported - // 2) field name matches base type name and is not exported - // 3) field name doesn't match base type name (alias name) - bname := basetypeName(f.Type()) - if name == bname { - if token.IsExported(name) { - name = "" // 1) we don't need to know the field name or package - } else { - name = "?" // 2) use unexported name "?" to force package export - } - } else { - // 3) indicate alias and export name as is - // (this requires an extra "@" but this is a rare case) - p.string("@") - } - } - - p.string(name) - if name != "" && !token.IsExported(name) { - p.pkg(f.Pkg(), false) - } -} - -func basetypeName(typ types.Type) string { - switch typ := deref(typ).(type) { - case *types.Basic: - return typ.Name() - case *types.Named: - return typ.Obj().Name() - default: - return "" // unnamed type - } -} - -func (p *exporter) paramList(params *types.Tuple, variadic bool) { - // use negative length to indicate unnamed parameters - // (look at the first parameter only since either all - // names are present or all are absent) - n := params.Len() - if n > 0 && params.At(0).Name() == "" { - n = -n - } - p.int(n) - for i := 0; i < params.Len(); i++ { - q := params.At(i) - t := q.Type() - if variadic && i == params.Len()-1 { - t = &dddSlice{t.(*types.Slice).Elem()} - } - p.typ(t) - if n > 0 { - name := q.Name() - p.string(name) - if name != "_" { - p.pkg(q.Pkg(), false) - } - } - p.string("") // no compiler-specific info - } -} - -func (p *exporter) value(x constant.Value) { - if trace { - p.tracef("= ") - } - - switch x.Kind() { - case constant.Bool: - tag := falseTag - if constant.BoolVal(x) { - tag = trueTag - } - p.tag(tag) - - case constant.Int: - if v, exact := constant.Int64Val(x); exact { - // common case: x fits into an int64 - use compact encoding - p.tag(int64Tag) - p.int64(v) - return - } - // uncommon case: large x - use float encoding - // (powers of 2 will be encoded efficiently with exponent) - p.tag(floatTag) - p.float(constant.ToFloat(x)) - - case constant.Float: - p.tag(floatTag) - p.float(x) - - case constant.Complex: - p.tag(complexTag) - p.float(constant.Real(x)) - p.float(constant.Imag(x)) - - case constant.String: - p.tag(stringTag) - p.string(constant.StringVal(x)) - - case constant.Unknown: - // package contains type errors - p.tag(unknownTag) - - default: - panic(internalErrorf("unexpected value %v (%T)", x, x)) - } -} - -func (p *exporter) float(x constant.Value) { - if x.Kind() != constant.Float { - panic(internalErrorf("unexpected constant %v, want float", x)) - } - // extract sign (there is no -0) - sign := constant.Sign(x) - if sign == 0 { - // x == 0 - p.int(0) - return - } - // x != 0 - - var f big.Float - if v, exact := constant.Float64Val(x); exact { - // float64 - f.SetFloat64(v) - } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { - // TODO(gri): add big.Rat accessor to constant.Value. - r := valueToRat(num) - f.SetRat(r.Quo(r, valueToRat(denom))) - } else { - // Value too large to represent as a fraction => inaccessible. - // TODO(gri): add big.Float accessor to constant.Value. - f.SetFloat64(math.MaxFloat64) // FIXME - } - - // extract exponent such that 0.5 <= m < 1.0 - var m big.Float - exp := f.MantExp(&m) - - // extract mantissa as *big.Int - // - set exponent large enough so mant satisfies mant.IsInt() - // - get *big.Int from mant - m.SetMantExp(&m, int(m.MinPrec())) - mant, acc := m.Int(nil) - if acc != big.Exact { - panic(internalError("internal error")) - } - - p.int(sign) - p.int(exp) - p.string(string(mant.Bytes())) -} - -func valueToRat(x constant.Value) *big.Rat { - // Convert little-endian to big-endian. - // I can't believe this is necessary. - bytes := constant.Bytes(x) - for i := 0; i < len(bytes)/2; i++ { - bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] - } - return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) -} - -func (p *exporter) bool(b bool) bool { - if trace { - p.tracef("[") - defer p.tracef("= %v] ", b) - } - - x := 0 - if b { - x = 1 - } - p.int(x) - return b -} - -// ---------------------------------------------------------------------------- -// Low-level encoders - -func (p *exporter) index(marker byte, index int) { - if index < 0 { - panic(internalError("invalid index < 0")) - } - if debugFormat { - p.marker('t') - } - if trace { - p.tracef("%c%d ", marker, index) - } - p.rawInt64(int64(index)) -} - -func (p *exporter) tag(tag int) { - if tag >= 0 { - panic(internalError("invalid tag >= 0")) - } - if debugFormat { - p.marker('t') - } - if trace { - p.tracef("%s ", tagString[-tag]) - } - p.rawInt64(int64(tag)) -} - -func (p *exporter) int(x int) { - p.int64(int64(x)) -} - -func (p *exporter) int64(x int64) { - if debugFormat { - p.marker('i') - } - if trace { - p.tracef("%d ", x) - } - p.rawInt64(x) -} - -func (p *exporter) string(s string) { - if debugFormat { - p.marker('s') - } - if trace { - p.tracef("%q ", s) - } - // if we saw the string before, write its index (>= 0) - // (the empty string is mapped to 0) - if i, ok := p.strIndex[s]; ok { - p.rawInt64(int64(i)) - return - } - // otherwise, remember string and write its negative length and bytes - p.strIndex[s] = len(p.strIndex) - p.rawInt64(-int64(len(s))) - for i := 0; i < len(s); i++ { - p.rawByte(s[i]) - } -} - -// marker emits a marker byte and position information which makes -// it easy for a reader to detect if it is "out of sync". Used for -// debugFormat format only. -func (p *exporter) marker(m byte) { - p.rawByte(m) - // Enable this for help tracking down the location - // of an incorrect marker when running in debugFormat. - if false && trace { - p.tracef("#%d ", p.written) - } - p.rawInt64(int64(p.written)) -} - -// rawInt64 should only be used by low-level encoders. -func (p *exporter) rawInt64(x int64) { - var tmp [binary.MaxVarintLen64]byte - n := binary.PutVarint(tmp[:], x) - for i := 0; i < n; i++ { - p.rawByte(tmp[i]) - } -} - -// rawStringln should only be used to emit the initial version string. -func (p *exporter) rawStringln(s string) { - for i := 0; i < len(s); i++ { - p.rawByte(s[i]) - } - p.rawByte('\n') -} - -// rawByte is the bottleneck interface to write to p.out. -// rawByte escapes b as follows (any encoding does that -// hides '$'): -// -// '$' => '|' 'S' -// '|' => '|' '|' -// -// Necessary so other tools can find the end of the -// export data by searching for "$$". -// rawByte should only be used by low-level encoders. -func (p *exporter) rawByte(b byte) { - switch b { - case '$': - // write '$' as '|' 'S' - b = 'S' - fallthrough - case '|': - // write '|' as '|' '|' - p.out.WriteByte('|') - p.written++ - } - p.out.WriteByte(b) - p.written++ -} - -// tracef is like fmt.Printf but it rewrites the format string -// to take care of indentation. -func (p *exporter) tracef(format string, args ...interface{}) { - if strings.ContainsAny(format, "<>\n") { - var buf bytes.Buffer - for i := 0; i < len(format); i++ { - // no need to deal with runes - ch := format[i] - switch ch { - case '>': - p.indent++ - continue - case '<': - p.indent-- - continue - } - buf.WriteByte(ch) - if ch == '\n' { - for j := p.indent; j > 0; j-- { - buf.WriteString(". ") - } - } - } - format = buf.String() - } - fmt.Printf(format, args...) -} - -// Debugging support. -// (tagString is only used when tracing is enabled) -var tagString = [...]string{ - // Packages - -packageTag: "package", - - // Types - -namedTag: "named type", - -arrayTag: "array", - -sliceTag: "slice", - -dddTag: "ddd", - -structTag: "struct", - -pointerTag: "pointer", - -signatureTag: "signature", - -interfaceTag: "interface", - -mapTag: "map", - -chanTag: "chan", - - // Values - -falseTag: "false", - -trueTag: "true", - -int64Tag: "int64", - -floatTag: "float", - -fractionTag: "fraction", - -complexTag: "complex", - -stringTag: "string", - -unknownTag: "unknown", - - // Type aliases - -aliasTag: "alias", -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/bimport.go b/vendor/golang.org/x/tools/internal/gcimporter/bimport.go index b85de0147..d98b0db2a 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/bimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/bimport.go @@ -2,340 +2,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file is a copy of $GOROOT/src/go/internal/gcimporter/bimport.go. +// This file contains the remaining vestiges of +// $GOROOT/src/go/internal/gcimporter/bimport.go. package gcimporter import ( - "encoding/binary" "fmt" - "go/constant" "go/token" "go/types" - "sort" - "strconv" - "strings" "sync" - "unicode" - "unicode/utf8" ) -type importer struct { - imports map[string]*types.Package - data []byte - importpath string - buf []byte // for reading strings - version int // export format version - - // object lists - strList []string // in order of appearance - pathList []string // in order of appearance - pkgList []*types.Package // in order of appearance - typList []types.Type // in order of appearance - interfaceList []*types.Interface // for delayed completion only - trackAllTypes bool - - // position encoding - posInfoFormat bool - prevFile string - prevLine int - fake fakeFileSet - - // debugging support - debugFormat bool - read int // bytes read -} - -// BImportData imports a package from the serialized package data -// and returns the number of bytes consumed and a reference to the package. -// If the export data version is not recognized or the format is otherwise -// compromised, an error is returned. -func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - // catch panics and return them as errors - const currentVersion = 6 - version := -1 // unknown version - defer func() { - if e := recover(); e != nil { - // Return a (possibly nil or incomplete) package unchanged (see #16088). - if version > currentVersion { - err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) - } else { - err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) - } - } - }() - - p := importer{ - imports: imports, - data: data, - importpath: path, - version: version, - strList: []string{""}, // empty string is mapped to 0 - pathList: []string{""}, // empty string is mapped to 0 - fake: fakeFileSet{ - fset: fset, - files: make(map[string]*fileInfo), - }, - } - defer p.fake.setLines() // set lines for files in fset - - // read version info - var versionstr string - if b := p.rawByte(); b == 'c' || b == 'd' { - // Go1.7 encoding; first byte encodes low-level - // encoding format (compact vs debug). - // For backward-compatibility only (avoid problems with - // old installed packages). Newly compiled packages use - // the extensible format string. - // TODO(gri) Remove this support eventually; after Go1.8. - if b == 'd' { - p.debugFormat = true - } - p.trackAllTypes = p.rawByte() == 'a' - p.posInfoFormat = p.int() != 0 - versionstr = p.string() - if versionstr == "v1" { - version = 0 - } - } else { - // Go1.8 extensible encoding - // read version string and extract version number (ignore anything after the version number) - versionstr = p.rawStringln(b) - if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" { - if v, err := strconv.Atoi(s[1]); err == nil && v > 0 { - version = v - } - } - } - p.version = version - - // read version specific flags - extend as necessary - switch p.version { - // case currentVersion: - // ... - // fallthrough - case currentVersion, 5, 4, 3, 2, 1: - p.debugFormat = p.rawStringln(p.rawByte()) == "debug" - p.trackAllTypes = p.int() != 0 - p.posInfoFormat = p.int() != 0 - case 0: - // Go1.7 encoding format - nothing to do here - default: - errorf("unknown bexport format version %d (%q)", p.version, versionstr) - } - - // --- generic export data --- - - // populate typList with predeclared "known" types - p.typList = append(p.typList, predeclared()...) - - // read package data - pkg = p.pkg() - - // read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go) - objcount := 0 - for { - tag := p.tagOrIndex() - if tag == endTag { - break - } - p.obj(tag) - objcount++ - } - - // self-verification - if count := p.int(); count != objcount { - errorf("got %d objects; want %d", objcount, count) - } - - // ignore compiler-specific import data - - // complete interfaces - // TODO(gri) re-investigate if we still need to do this in a delayed fashion - for _, typ := range p.interfaceList { - typ.Complete() - } - - // record all referenced packages as imports - list := append(([]*types.Package)(nil), p.pkgList[1:]...) - sort.Sort(byPath(list)) - pkg.SetImports(list) - - // package was imported completely and without errors - pkg.MarkComplete() - - return p.read, pkg, nil -} - func errorf(format string, args ...interface{}) { panic(fmt.Sprintf(format, args...)) } -func (p *importer) pkg() *types.Package { - // if the package was seen before, i is its index (>= 0) - i := p.tagOrIndex() - if i >= 0 { - return p.pkgList[i] - } - - // otherwise, i is the package tag (< 0) - if i != packageTag { - errorf("unexpected package tag %d version %d", i, p.version) - } - - // read package data - name := p.string() - var path string - if p.version >= 5 { - path = p.path() - } else { - path = p.string() - } - if p.version >= 6 { - p.int() // package height; unused by go/types - } - - // we should never see an empty package name - if name == "" { - errorf("empty package name in import") - } - - // an empty path denotes the package we are currently importing; - // it must be the first package we see - if (path == "") != (len(p.pkgList) == 0) { - errorf("package path %q for pkg index %d", path, len(p.pkgList)) - } - - // if the package was imported before, use that one; otherwise create a new one - if path == "" { - path = p.importpath - } - pkg := p.imports[path] - if pkg == nil { - pkg = types.NewPackage(path, name) - p.imports[path] = pkg - } else if pkg.Name() != name { - errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path) - } - p.pkgList = append(p.pkgList, pkg) - - return pkg -} - -// objTag returns the tag value for each object kind. -func objTag(obj types.Object) int { - switch obj.(type) { - case *types.Const: - return constTag - case *types.TypeName: - return typeTag - case *types.Var: - return varTag - case *types.Func: - return funcTag - default: - errorf("unexpected object: %v (%T)", obj, obj) // panics - panic("unreachable") - } -} - -func sameObj(a, b types.Object) bool { - // Because unnamed types are not canonicalized, we cannot simply compare types for - // (pointer) identity. - // Ideally we'd check equality of constant values as well, but this is good enough. - return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type()) -} - -func (p *importer) declare(obj types.Object) { - pkg := obj.Pkg() - if alt := pkg.Scope().Insert(obj); alt != nil { - // This can only trigger if we import a (non-type) object a second time. - // Excluding type aliases, this cannot happen because 1) we only import a package - // once; and b) we ignore compiler-specific export data which may contain - // functions whose inlined function bodies refer to other functions that - // were already imported. - // However, type aliases require reexporting the original type, so we need - // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go, - // method importer.obj, switch case importing functions). - // TODO(gri) review/update this comment once the gc compiler handles type aliases. - if !sameObj(obj, alt) { - errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt) - } - } -} - -func (p *importer) obj(tag int) { - switch tag { - case constTag: - pos := p.pos() - pkg, name := p.qualifiedName() - typ := p.typ(nil, nil) - val := p.value() - p.declare(types.NewConst(pos, pkg, name, typ, val)) - - case aliasTag: - // TODO(gri) verify type alias hookup is correct - pos := p.pos() - pkg, name := p.qualifiedName() - typ := p.typ(nil, nil) - p.declare(types.NewTypeName(pos, pkg, name, typ)) - - case typeTag: - p.typ(nil, nil) - - case varTag: - pos := p.pos() - pkg, name := p.qualifiedName() - typ := p.typ(nil, nil) - p.declare(types.NewVar(pos, pkg, name, typ)) - - case funcTag: - pos := p.pos() - pkg, name := p.qualifiedName() - params, isddd := p.paramList() - result, _ := p.paramList() - sig := types.NewSignature(nil, params, result, isddd) - p.declare(types.NewFunc(pos, pkg, name, sig)) - - default: - errorf("unexpected object tag %d", tag) - } -} - const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go -func (p *importer) pos() token.Pos { - if !p.posInfoFormat { - return token.NoPos - } - - file := p.prevFile - line := p.prevLine - delta := p.int() - line += delta - if p.version >= 5 { - if delta == deltaNewFile { - if n := p.int(); n >= 0 { - // file changed - file = p.path() - line = n - } - } - } else { - if delta == 0 { - if n := p.int(); n >= 0 { - // file changed - file = p.prevFile[:n] + p.string() - line = p.int() - } - } - } - p.prevFile = file - p.prevLine = line - - return p.fake.pos(file, line, 0) -} - // Synthesize a token.Pos type fakeFileSet struct { fset *token.FileSet @@ -389,205 +73,6 @@ var ( fakeLinesOnce sync.Once ) -func (p *importer) qualifiedName() (pkg *types.Package, name string) { - name = p.string() - pkg = p.pkg() - return -} - -func (p *importer) record(t types.Type) { - p.typList = append(p.typList, t) -} - -// A dddSlice is a types.Type representing ...T parameters. -// It only appears for parameter types and does not escape -// the importer. -type dddSlice struct { - elem types.Type -} - -func (t *dddSlice) Underlying() types.Type { return t } -func (t *dddSlice) String() string { return "..." + t.elem.String() } - -// parent is the package which declared the type; parent == nil means -// the package currently imported. The parent package is needed for -// exported struct fields and interface methods which don't contain -// explicit package information in the export data. -// -// A non-nil tname is used as the "owner" of the result type; i.e., -// the result type is the underlying type of tname. tname is used -// to give interface methods a named receiver type where possible. -func (p *importer) typ(parent *types.Package, tname *types.Named) types.Type { - // if the type was seen before, i is its index (>= 0) - i := p.tagOrIndex() - if i >= 0 { - return p.typList[i] - } - - // otherwise, i is the type tag (< 0) - switch i { - case namedTag: - // read type object - pos := p.pos() - parent, name := p.qualifiedName() - scope := parent.Scope() - obj := scope.Lookup(name) - - // if the object doesn't exist yet, create and insert it - if obj == nil { - obj = types.NewTypeName(pos, parent, name, nil) - scope.Insert(obj) - } - - if _, ok := obj.(*types.TypeName); !ok { - errorf("pkg = %s, name = %s => %s", parent, name, obj) - } - - // associate new named type with obj if it doesn't exist yet - t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) - - // but record the existing type, if any - tname := obj.Type().(*types.Named) // tname is either t0 or the existing type - p.record(tname) - - // read underlying type - t0.SetUnderlying(p.typ(parent, t0)) - - // interfaces don't have associated methods - if types.IsInterface(t0) { - return tname - } - - // read associated methods - for i := p.int(); i > 0; i-- { - // TODO(gri) replace this with something closer to fieldName - pos := p.pos() - name := p.string() - if !exported(name) { - p.pkg() - } - - recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? - params, isddd := p.paramList() - result, _ := p.paramList() - p.int() // go:nointerface pragma - discarded - - sig := types.NewSignature(recv.At(0), params, result, isddd) - t0.AddMethod(types.NewFunc(pos, parent, name, sig)) - } - - return tname - - case arrayTag: - t := new(types.Array) - if p.trackAllTypes { - p.record(t) - } - - n := p.int64() - *t = *types.NewArray(p.typ(parent, nil), n) - return t - - case sliceTag: - t := new(types.Slice) - if p.trackAllTypes { - p.record(t) - } - - *t = *types.NewSlice(p.typ(parent, nil)) - return t - - case dddTag: - t := new(dddSlice) - if p.trackAllTypes { - p.record(t) - } - - t.elem = p.typ(parent, nil) - return t - - case structTag: - t := new(types.Struct) - if p.trackAllTypes { - p.record(t) - } - - *t = *types.NewStruct(p.fieldList(parent)) - return t - - case pointerTag: - t := new(types.Pointer) - if p.trackAllTypes { - p.record(t) - } - - *t = *types.NewPointer(p.typ(parent, nil)) - return t - - case signatureTag: - t := new(types.Signature) - if p.trackAllTypes { - p.record(t) - } - - params, isddd := p.paramList() - result, _ := p.paramList() - *t = *types.NewSignature(nil, params, result, isddd) - return t - - case interfaceTag: - // Create a dummy entry in the type list. This is safe because we - // cannot expect the interface type to appear in a cycle, as any - // such cycle must contain a named type which would have been - // first defined earlier. - // TODO(gri) Is this still true now that we have type aliases? - // See issue #23225. - n := len(p.typList) - if p.trackAllTypes { - p.record(nil) - } - - var embeddeds []types.Type - for n := p.int(); n > 0; n-- { - p.pos() - embeddeds = append(embeddeds, p.typ(parent, nil)) - } - - t := newInterface(p.methodList(parent, tname), embeddeds) - p.interfaceList = append(p.interfaceList, t) - if p.trackAllTypes { - p.typList[n] = t - } - return t - - case mapTag: - t := new(types.Map) - if p.trackAllTypes { - p.record(t) - } - - key := p.typ(parent, nil) - val := p.typ(parent, nil) - *t = *types.NewMap(key, val) - return t - - case chanTag: - t := new(types.Chan) - if p.trackAllTypes { - p.record(t) - } - - dir := chanDir(p.int()) - val := p.typ(parent, nil) - *t = *types.NewChan(dir, val) - return t - - default: - errorf("unexpected type tag %d", i) // panics - panic("unreachable") - } -} - func chanDir(d int) types.ChanDir { // tag values must match the constants in cmd/compile/internal/gc/go.go switch d { @@ -603,394 +88,6 @@ func chanDir(d int) types.ChanDir { } } -func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) { - if n := p.int(); n > 0 { - fields = make([]*types.Var, n) - tags = make([]string, n) - for i := range fields { - fields[i], tags[i] = p.field(parent) - } - } - return -} - -func (p *importer) field(parent *types.Package) (*types.Var, string) { - pos := p.pos() - pkg, name, alias := p.fieldName(parent) - typ := p.typ(parent, nil) - tag := p.string() - - anonymous := false - if name == "" { - // anonymous field - typ must be T or *T and T must be a type name - switch typ := deref(typ).(type) { - case *types.Basic: // basic types are named types - pkg = nil // // objects defined in Universe scope have no package - name = typ.Name() - case *types.Named: - name = typ.Obj().Name() - default: - errorf("named base type expected") - } - anonymous = true - } else if alias { - // anonymous field: we have an explicit name because it's an alias - anonymous = true - } - - return types.NewField(pos, pkg, name, typ, anonymous), tag -} - -func (p *importer) methodList(parent *types.Package, baseType *types.Named) (methods []*types.Func) { - if n := p.int(); n > 0 { - methods = make([]*types.Func, n) - for i := range methods { - methods[i] = p.method(parent, baseType) - } - } - return -} - -func (p *importer) method(parent *types.Package, baseType *types.Named) *types.Func { - pos := p.pos() - pkg, name, _ := p.fieldName(parent) - // If we don't have a baseType, use a nil receiver. - // A receiver using the actual interface type (which - // we don't know yet) will be filled in when we call - // types.Interface.Complete. - var recv *types.Var - if baseType != nil { - recv = types.NewVar(token.NoPos, parent, "", baseType) - } - params, isddd := p.paramList() - result, _ := p.paramList() - sig := types.NewSignature(recv, params, result, isddd) - return types.NewFunc(pos, pkg, name, sig) -} - -func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) { - name = p.string() - pkg = parent - if pkg == nil { - // use the imported package instead - pkg = p.pkgList[0] - } - if p.version == 0 && name == "_" { - // version 0 didn't export a package for _ fields - return - } - switch name { - case "": - // 1) field name matches base type name and is exported: nothing to do - case "?": - // 2) field name matches base type name and is not exported: need package - name = "" - pkg = p.pkg() - case "@": - // 3) field name doesn't match type name (alias) - name = p.string() - alias = true - fallthrough - default: - if !exported(name) { - pkg = p.pkg() - } - } - return -} - -func (p *importer) paramList() (*types.Tuple, bool) { - n := p.int() - if n == 0 { - return nil, false - } - // negative length indicates unnamed parameters - named := true - if n < 0 { - n = -n - named = false - } - // n > 0 - params := make([]*types.Var, n) - isddd := false - for i := range params { - params[i], isddd = p.param(named) - } - return types.NewTuple(params...), isddd -} - -func (p *importer) param(named bool) (*types.Var, bool) { - t := p.typ(nil, nil) - td, isddd := t.(*dddSlice) - if isddd { - t = types.NewSlice(td.elem) - } - - var pkg *types.Package - var name string - if named { - name = p.string() - if name == "" { - errorf("expected named parameter") - } - if name != "_" { - pkg = p.pkg() - } - if i := strings.Index(name, "·"); i > 0 { - name = name[:i] // cut off gc-specific parameter numbering - } - } - - // read and discard compiler-specific info - p.string() - - return types.NewVar(token.NoPos, pkg, name, t), isddd -} - -func exported(name string) bool { - ch, _ := utf8.DecodeRuneInString(name) - return unicode.IsUpper(ch) -} - -func (p *importer) value() constant.Value { - switch tag := p.tagOrIndex(); tag { - case falseTag: - return constant.MakeBool(false) - case trueTag: - return constant.MakeBool(true) - case int64Tag: - return constant.MakeInt64(p.int64()) - case floatTag: - return p.float() - case complexTag: - re := p.float() - im := p.float() - return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) - case stringTag: - return constant.MakeString(p.string()) - case unknownTag: - return constant.MakeUnknown() - default: - errorf("unexpected value tag %d", tag) // panics - panic("unreachable") - } -} - -func (p *importer) float() constant.Value { - sign := p.int() - if sign == 0 { - return constant.MakeInt64(0) - } - - exp := p.int() - mant := []byte(p.string()) // big endian - - // remove leading 0's if any - for len(mant) > 0 && mant[0] == 0 { - mant = mant[1:] - } - - // convert to little endian - // TODO(gri) go/constant should have a more direct conversion function - // (e.g., once it supports a big.Float based implementation) - for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 { - mant[i], mant[j] = mant[j], mant[i] - } - - // adjust exponent (constant.MakeFromBytes creates an integer value, - // but mant represents the mantissa bits such that 0.5 <= mant < 1.0) - exp -= len(mant) << 3 - if len(mant) > 0 { - for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 { - exp++ - } - } - - x := constant.MakeFromBytes(mant) - switch { - case exp < 0: - d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) - x = constant.BinaryOp(x, token.QUO, d) - case exp > 0: - x = constant.Shift(x, token.SHL, uint(exp)) - } - - if sign < 0 { - x = constant.UnaryOp(token.SUB, x, 0) - } - return x -} - -// ---------------------------------------------------------------------------- -// Low-level decoders - -func (p *importer) tagOrIndex() int { - if p.debugFormat { - p.marker('t') - } - - return int(p.rawInt64()) -} - -func (p *importer) int() int { - x := p.int64() - if int64(int(x)) != x { - errorf("exported integer too large") - } - return int(x) -} - -func (p *importer) int64() int64 { - if p.debugFormat { - p.marker('i') - } - - return p.rawInt64() -} - -func (p *importer) path() string { - if p.debugFormat { - p.marker('p') - } - // if the path was seen before, i is its index (>= 0) - // (the empty string is at index 0) - i := p.rawInt64() - if i >= 0 { - return p.pathList[i] - } - // otherwise, i is the negative path length (< 0) - a := make([]string, -i) - for n := range a { - a[n] = p.string() - } - s := strings.Join(a, "/") - p.pathList = append(p.pathList, s) - return s -} - -func (p *importer) string() string { - if p.debugFormat { - p.marker('s') - } - // if the string was seen before, i is its index (>= 0) - // (the empty string is at index 0) - i := p.rawInt64() - if i >= 0 { - return p.strList[i] - } - // otherwise, i is the negative string length (< 0) - if n := int(-i); n <= cap(p.buf) { - p.buf = p.buf[:n] - } else { - p.buf = make([]byte, n) - } - for i := range p.buf { - p.buf[i] = p.rawByte() - } - s := string(p.buf) - p.strList = append(p.strList, s) - return s -} - -func (p *importer) marker(want byte) { - if got := p.rawByte(); got != want { - errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read) - } - - pos := p.read - if n := int(p.rawInt64()); n != pos { - errorf("incorrect position: got %d; want %d", n, pos) - } -} - -// rawInt64 should only be used by low-level decoders. -func (p *importer) rawInt64() int64 { - i, err := binary.ReadVarint(p) - if err != nil { - errorf("read error: %v", err) - } - return i -} - -// rawStringln should only be used to read the initial version string. -func (p *importer) rawStringln(b byte) string { - p.buf = p.buf[:0] - for b != '\n' { - p.buf = append(p.buf, b) - b = p.rawByte() - } - return string(p.buf) -} - -// needed for binary.ReadVarint in rawInt64 -func (p *importer) ReadByte() (byte, error) { - return p.rawByte(), nil -} - -// byte is the bottleneck interface for reading p.data. -// It unescapes '|' 'S' to '$' and '|' '|' to '|'. -// rawByte should only be used by low-level decoders. -func (p *importer) rawByte() byte { - b := p.data[0] - r := 1 - if b == '|' { - b = p.data[1] - r = 2 - switch b { - case 'S': - b = '$' - case '|': - // nothing to do - default: - errorf("unexpected escape sequence in export data") - } - } - p.data = p.data[r:] - p.read += r - return b - -} - -// ---------------------------------------------------------------------------- -// Export format - -// Tags. Must be < 0. -const ( - // Objects - packageTag = -(iota + 1) - constTag - typeTag - varTag - funcTag - endTag - - // Types - namedTag - arrayTag - sliceTag - dddTag - structTag - pointerTag - signatureTag - interfaceTag - mapTag - chanTag - - // Values - falseTag - trueTag - int64Tag - floatTag - fractionTag // not used by gc - complexTag - stringTag - nilTag // only used by gc (appears in exported inlined function bodies) - unknownTag // not used by gc (only appears in packages with errors) - - // Type aliases - aliasTag -) - var predeclOnce sync.Once var predecl []types.Type // initialized lazily diff --git a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go index a973dece9..2d078ccb1 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go @@ -29,7 +29,6 @@ import ( "go/token" "go/types" "io" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -221,7 +220,7 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func switch hdr { case "$$B\n": var data []byte - data, err = ioutil.ReadAll(buf) + data, err = io.ReadAll(buf) if err != nil { break } @@ -230,20 +229,17 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func // Or, define a new standard go/types/gcexportdata package. fset := token.NewFileSet() - // The indexed export format starts with an 'i'; the older - // binary export format starts with a 'c', 'd', or 'v' - // (from "version"). Select appropriate importer. + // Select appropriate importer. if len(data) > 0 { switch data[0] { - case 'i': - _, pkg, err := IImportData(fset, packages, data[1:], id) - return pkg, err + case 'v', 'c', 'd': // binary, till go1.10 + return nil, fmt.Errorf("binary (%c) import format is no longer supported", data[0]) - case 'v', 'c', 'd': - _, pkg, err := BImportData(fset, packages, data, id) + case 'i': // indexed, till go1.19 + _, pkg, err := IImportData(fset, packages, data[1:], id) return pkg, err - case 'u': + case 'u': // unified, from go1.20 _, pkg, err := UImportData(fset, packages, data[1:size], id) return pkg, err diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index a0dc0b5e2..2ee8c7016 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -22,17 +22,22 @@ import ( "strconv" "strings" + "golang.org/x/tools/go/types/objectpath" "golang.org/x/tools/internal/tokeninternal" - "golang.org/x/tools/internal/typeparams" ) // IExportShallow encodes "shallow" export data for the specified package. // -// No promises are made about the encoding other than that it can be -// decoded by the same version of IIExportShallow. If you plan to save -// export data in the file system, be sure to include a cryptographic -// digest of the executable in the key to avoid version skew. -func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { +// No promises are made about the encoding other than that it can be decoded by +// the same version of IIExportShallow. If you plan to save export data in the +// file system, be sure to include a cryptographic digest of the executable in +// the key to avoid version skew. +// +// If the provided reportf func is non-nil, it will be used for reporting bugs +// encountered during export. +// TODO(rfindley): remove reportf when we are confident enough in the new +// objectpath encoding. +func IExportShallow(fset *token.FileSet, pkg *types.Package, reportf ReportFunc) ([]byte, error) { // In principle this operation can only fail if out.Write fails, // but that's impossible for bytes.Buffer---and as a matter of // fact iexportCommon doesn't even check for I/O errors. @@ -47,19 +52,27 @@ func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { // IImportShallow decodes "shallow" types.Package data encoded by // IExportShallow in the same executable. This function cannot import data from // cmd/compile or gcexportdata.Write. -func IImportShallow(fset *token.FileSet, getPackage GetPackageFunc, data []byte, path string, insert InsertType) (*types.Package, error) { +// +// The importer calls getPackages to obtain package symbols for all +// packages mentioned in the export data, including the one being +// decoded. +// +// If the provided reportf func is non-nil, it will be used for reporting bugs +// encountered during import. +// TODO(rfindley): remove reportf when we are confident enough in the new +// objectpath encoding. +func IImportShallow(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, path string, reportf ReportFunc) (*types.Package, error) { const bundle = false - pkgs, err := iimportCommon(fset, getPackage, data, bundle, path, insert) + const shallow = true + pkgs, err := iimportCommon(fset, getPackages, data, bundle, path, shallow, reportf) if err != nil { return nil, err } return pkgs[0], nil } -// InsertType is the type of a function that creates a types.TypeName -// object for a named type and inserts it into the scope of the -// specified Package. -type InsertType = func(pkg *types.Package, name string) +// ReportFunc is the type of a function used to report formatted bugs. +type ReportFunc = func(string, ...interface{}) // Current bundled export format version. Increase with each format change. // 0: initial implementation @@ -313,8 +326,9 @@ type iexporter struct { out *bytes.Buffer version int - shallow bool // don't put types from other packages in the index - localpkg *types.Package // (nil in bundle mode) + shallow bool // don't put types from other packages in the index + objEncoder *objectpath.Encoder // encodes objects from other packages in shallow mode; lazily allocated + localpkg *types.Package // (nil in bundle mode) // allPkgs tracks all packages that have been referenced by // the export data, so we can ensure to include them in the @@ -354,6 +368,17 @@ func (p *iexporter) trace(format string, args ...interface{}) { fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...) } +// objectpathEncoder returns the lazily allocated objectpath.Encoder to use +// when encoding objects in other packages during shallow export. +// +// Using a shared Encoder amortizes some of cost of objectpath search. +func (p *iexporter) objectpathEncoder() *objectpath.Encoder { + if p.objEncoder == nil { + p.objEncoder = new(objectpath.Encoder) + } + return p.objEncoder +} + // stringOff returns the offset of s within the string section. // If not already present, it's added to the end. func (p *iexporter) stringOff(s string) uint64 { @@ -413,7 +438,6 @@ type exportWriter struct { p *iexporter data intWriter - currPkg *types.Package prevFile string prevLine int64 prevColumn int64 @@ -436,7 +460,6 @@ func (p *iexporter) doDecl(obj types.Object) { }() } w := p.newWriter() - w.setPkg(obj.Pkg(), false) switch obj := obj.(type) { case *types.Var: @@ -457,7 +480,7 @@ func (p *iexporter) doDecl(obj types.Object) { } // Function. - if typeparams.ForSignature(sig).Len() == 0 { + if sig.TypeParams().Len() == 0 { w.tag('F') } else { w.tag('G') @@ -470,7 +493,7 @@ func (p *iexporter) doDecl(obj types.Object) { // // While importing the type parameters, tparamList computes and records // their export name, so that it can be later used when writing the index. - if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 { + if tparams := sig.TypeParams(); tparams.Len() > 0 { w.tparamList(obj.Name(), tparams, obj.Pkg()) } w.signature(sig) @@ -483,14 +506,14 @@ func (p *iexporter) doDecl(obj types.Object) { case *types.TypeName: t := obj.Type() - if tparam, ok := t.(*typeparams.TypeParam); ok { + if tparam, ok := t.(*types.TypeParam); ok { w.tag('P') w.pos(obj.Pos()) constraint := tparam.Constraint() if p.version >= iexportVersionGo1_18 { implicit := false if iface, _ := constraint.(*types.Interface); iface != nil { - implicit = typeparams.IsImplicit(iface) + implicit = iface.IsImplicit() } w.bool(implicit) } @@ -511,17 +534,17 @@ func (p *iexporter) doDecl(obj types.Object) { panic(internalErrorf("%s is not a defined type", t)) } - if typeparams.ForNamed(named).Len() == 0 { + if named.TypeParams().Len() == 0 { w.tag('T') } else { w.tag('U') } w.pos(obj.Pos()) - if typeparams.ForNamed(named).Len() > 0 { + if named.TypeParams().Len() > 0 { // While importing the type parameters, tparamList computes and records // their export name, so that it can be later used when writing the index. - w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg()) + w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg()) } underlying := obj.Type().Underlying() @@ -541,7 +564,7 @@ func (p *iexporter) doDecl(obj types.Object) { // Receiver type parameters are type arguments of the receiver type, so // their name must be qualified before exporting recv. - if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 { + if rparams := sig.RecvTypeParams(); rparams.Len() > 0 { prefix := obj.Name() + "." + m.Name() for i := 0; i < rparams.Len(); i++ { rparam := rparams.At(i) @@ -673,6 +696,9 @@ func (w *exportWriter) qualifiedType(obj *types.TypeName) { w.pkg(obj.Pkg()) } +// TODO(rfindley): what does 'pkg' even mean here? It would be better to pass +// it in explicitly into signatures and structs that may use it for +// constructing fields. func (w *exportWriter) typ(t types.Type, pkg *types.Package) { w.data.uint64(w.p.typOff(t, pkg)) } @@ -713,19 +739,19 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { } switch t := t.(type) { case *types.Named: - if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 { + if targs := t.TypeArgs(); targs.Len() > 0 { w.startType(instanceType) // TODO(rfindley): investigate if this position is correct, and if it // matters. w.pos(t.Obj().Pos()) w.typeList(targs, pkg) - w.typ(typeparams.NamedTypeOrigin(t), pkg) + w.typ(t.Origin(), pkg) return } w.startType(definedType) w.qualifiedType(t.Obj()) - case *typeparams.TypeParam: + case *types.TypeParam: w.startType(typeParamType) w.qualifiedType(t.Obj()) @@ -764,30 +790,53 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { case *types.Signature: w.startType(signatureType) - w.setPkg(pkg, true) + w.pkg(pkg) w.signature(t) case *types.Struct: w.startType(structType) n := t.NumFields() + // Even for struct{} we must emit some qualifying package, because that's + // what the compiler does, and thus that's what the importer expects. + fieldPkg := pkg if n > 0 { - w.setPkg(t.Field(0).Pkg(), true) // qualifying package for field objects - } else { - w.setPkg(pkg, true) + fieldPkg = t.Field(0).Pkg() + } + if fieldPkg == nil { + // TODO(rfindley): improve this very hacky logic. + // + // The importer expects a package to be set for all struct types, even + // those with no fields. A better encoding might be to set NumFields + // before pkg. setPkg panics with a nil package, which may be possible + // to reach with invalid packages (and perhaps valid packages, too?), so + // (arbitrarily) set the localpkg if available. + // + // Alternatively, we may be able to simply guarantee that pkg != nil, by + // reconsidering the encoding of constant values. + if w.p.shallow { + fieldPkg = w.p.localpkg + } else { + panic(internalErrorf("no package to set for empty struct")) + } } + w.pkg(fieldPkg) w.uint64(uint64(n)) + for i := 0; i < n; i++ { f := t.Field(i) + if w.p.shallow { + w.objectPath(f) + } w.pos(f.Pos()) w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg - w.typ(f.Type(), pkg) + w.typ(f.Type(), fieldPkg) w.bool(f.Anonymous()) w.string(t.Tag(i)) // note (or tag) } case *types.Interface: w.startType(interfaceType) - w.setPkg(pkg, true) + w.pkg(pkg) n := t.NumEmbeddeds() w.uint64(uint64(n)) @@ -802,17 +851,23 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { w.typ(ft, tPkg) } + // See comment for struct fields. In shallow mode we change the encoding + // for interface methods that are promoted from other packages. + n = t.NumExplicitMethods() w.uint64(uint64(n)) for i := 0; i < n; i++ { m := t.ExplicitMethod(i) + if w.p.shallow { + w.objectPath(m) + } w.pos(m.Pos()) w.string(m.Name()) sig, _ := m.Type().(*types.Signature) w.signature(sig) } - case *typeparams.Union: + case *types.Union: w.startType(unionType) nt := t.Len() w.uint64(uint64(nt)) @@ -827,12 +882,61 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { } } -func (w *exportWriter) setPkg(pkg *types.Package, write bool) { - if write { - w.pkg(pkg) +// objectPath writes the package and objectPath to use to look up obj in a +// different package, when encoding in "shallow" mode. +// +// When doing a shallow import, the importer creates only the local package, +// and requests package symbols for dependencies from the client. +// However, certain types defined in the local package may hold objects defined +// (perhaps deeply) within another package. +// +// For example, consider the following: +// +// package a +// func F() chan * map[string] struct { X int } +// +// package b +// import "a" +// var B = a.F() +// +// In this example, the type of b.B holds fields defined in package a. +// In order to have the correct canonical objects for the field defined in the +// type of B, they are encoded as objectPaths and later looked up in the +// importer. The same problem applies to interface methods. +func (w *exportWriter) objectPath(obj types.Object) { + if obj.Pkg() == nil || obj.Pkg() == w.p.localpkg { + // obj.Pkg() may be nil for the builtin error.Error. + // In this case, or if obj is declared in the local package, no need to + // encode. + w.string("") + return } - - w.currPkg = pkg + objectPath, err := w.p.objectpathEncoder().For(obj) + if err != nil { + // Fall back to the empty string, which will cause the importer to create a + // new object, which matches earlier behavior. Creating a new object is + // sufficient for many purposes (such as type checking), but causes certain + // references algorithms to fail (golang/go#60819). However, we didn't + // notice this problem during months of gopls@v0.12.0 testing. + // + // TODO(golang/go#61674): this workaround is insufficient, as in the case + // where the field forwarded from an instantiated type that may not appear + // in the export data of the original package: + // + // // package a + // type A[P any] struct{ F P } + // + // // package b + // type B a.A[int] + // + // We need to update references algorithms not to depend on this + // de-duplication, at which point we may want to simply remove the + // workaround here. + w.string("") + return + } + w.string(string(objectPath)) + w.pkg(obj.Pkg()) } func (w *exportWriter) signature(sig *types.Signature) { @@ -843,14 +947,14 @@ func (w *exportWriter) signature(sig *types.Signature) { } } -func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) { +func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) { w.uint64(uint64(ts.Len())) for i := 0; i < ts.Len(); i++ { w.typ(ts.At(i), pkg) } } -func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) { +func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) { ll := uint64(list.Len()) w.uint64(ll) for i := 0; i < list.Len(); i++ { @@ -868,7 +972,7 @@ const blankMarker = "$" // differs from its actual object name: it is prefixed with a qualifier, and // blank type parameter names are disambiguated by their index in the type // parameter list. -func tparamExportName(prefix string, tparam *typeparams.TypeParam) string { +func tparamExportName(prefix string, tparam *types.TypeParam) string { assert(prefix != "") name := tparam.Obj().Name() if name == "_" { @@ -913,6 +1017,17 @@ func (w *exportWriter) value(typ types.Type, v constant.Value) { w.int64(int64(v.Kind())) } + if v.Kind() == constant.Unknown { + // golang/go#60605: treat unknown constant values as if they have invalid type + // + // This loses some fidelity over the package type-checked from source, but that + // is acceptable. + // + // TODO(rfindley): we should switch on the recorded constant kind rather + // than the constant type + return + } + switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { case types.IsBoolean: w.bool(constant.BoolVal(v)) @@ -969,6 +1084,16 @@ func constantToFloat(x constant.Value) *big.Float { return &f } +func valueToRat(x constant.Value) *big.Rat { + // Convert little-endian to big-endian. + // I can't believe this is necessary. + bytes := constant.Bytes(x) + for i := 0; i < len(bytes)/2; i++ { + bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] + } + return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) +} + // mpint exports a multi-precision integer. // // For unsigned types, small values are written out as a single @@ -1178,3 +1303,19 @@ func (q *objQueue) popHead() types.Object { q.head++ return obj } + +// internalError represents an error generated inside this package. +type internalError string + +func (e internalError) Error() string { return "gcimporter: " + string(e) } + +// TODO(adonovan): make this call panic, so that it's symmetric with errorf. +// Otherwise it's easy to forget to do anything with the error. +// +// TODO(adonovan): also, consider switching the names "errorf" and +// "internalErrorf" as the former is used for bugs, whose cause is +// internal inconsistency, whereas the latter is used for ordinary +// situations like bad input, whose cause is external. +func internalErrorf(format string, args ...interface{}) error { + return internalError(fmt.Sprintf(format, args...)) +} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index be6dace15..9bde15e3b 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -21,7 +21,7 @@ import ( "sort" "strings" - "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/go/types/objectpath" ) type intReader struct { @@ -85,7 +85,7 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { - pkgs, err := iimportCommon(fset, GetPackageFromMap(imports), data, false, path, nil) + pkgs, err := iimportCommon(fset, GetPackagesFromMap(imports), data, false, path, false, nil) if err != nil { return 0, nil, err } @@ -94,33 +94,49 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] // IImportBundle imports a set of packages from the serialized package bundle. func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { - return iimportCommon(fset, GetPackageFromMap(imports), data, true, "", nil) + return iimportCommon(fset, GetPackagesFromMap(imports), data, true, "", false, nil) } -// A GetPackageFunc is a function that gets the package with the given path -// from the importer state, creating it (with the specified name) if necessary. -// It is an abstraction of the map historically used to memoize package creation. +// A GetPackagesFunc function obtains the non-nil symbols for a set of +// packages, creating and recursively importing them as needed. An +// implementation should store each package symbol is in the Pkg +// field of the items array. // -// Two calls with the same path must return the same package. -// -// If the given getPackage func returns nil, the import will fail. -type GetPackageFunc = func(path, name string) *types.Package +// Any error causes importing to fail. This can be used to quickly read +// the import manifest of an export data file without fully decoding it. +type GetPackagesFunc = func(items []GetPackagesItem) error + +// A GetPackagesItem is a request from the importer for the package +// symbol of the specified name and path. +type GetPackagesItem struct { + Name, Path string + Pkg *types.Package // to be filled in by GetPackagesFunc call + + // private importer state + pathOffset uint64 + nameIndex map[string]uint64 +} -// GetPackageFromMap returns a GetPackageFunc that retrieves packages from the -// given map of package path -> package. +// GetPackagesFromMap returns a GetPackagesFunc that retrieves +// packages from the given map of package path to package. // -// The resulting func may mutate m: if a requested package is not found, a new -// package will be inserted into m. -func GetPackageFromMap(m map[string]*types.Package) GetPackageFunc { - return func(path, name string) *types.Package { - if _, ok := m[path]; !ok { - m[path] = types.NewPackage(path, name) +// The returned function may mutate m: each requested package that is not +// found is created with types.NewPackage and inserted into m. +func GetPackagesFromMap(m map[string]*types.Package) GetPackagesFunc { + return func(items []GetPackagesItem) error { + for i, item := range items { + pkg, ok := m[item.Path] + if !ok { + pkg = types.NewPackage(item.Path, item.Name) + m[item.Path] = pkg + } + items[i].Pkg = pkg } - return m[path] + return nil } } -func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { +func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, bundle bool, path string, shallow bool, reportf ReportFunc) (pkgs []*types.Package, err error) { const currentVersion = iexportVersionCurrent version := int64(-1) if !debug { @@ -131,7 +147,7 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, } else if version > currentVersion { err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) } else { - err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + err = fmt.Errorf("internal error while importing %q (%v); please report an issue", path, e) } } }() @@ -140,11 +156,8 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, r := &intReader{bytes.NewReader(data), path} if bundle { - bundleVersion := r.uint64() - switch bundleVersion { - case bundleVersion: - default: - errorf("unknown bundle format version %d", bundleVersion) + if v := r.uint64(); v != bundleVersion { + errorf("unknown bundle format version %d", v) } } @@ -162,7 +175,7 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, sLen := int64(r.uint64()) var fLen int64 var fileOffset []uint64 - if insert != nil { + if shallow { // Shallow mode uses a different position encoding. fLen = int64(r.uint64()) fileOffset = make([]uint64, r.uint64()) @@ -181,7 +194,8 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, p := iimporter{ version: int(version), ipath: path, - insert: insert, + shallow: shallow, + reportf: reportf, stringData: stringData, stringCache: make(map[uint64]string), @@ -208,8 +222,9 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, p.typCache[uint64(i)] = pt } - pkgList := make([]*types.Package, r.uint64()) - for i := range pkgList { + // Gather the relevant packages from the manifest. + items := make([]GetPackagesItem, r.uint64()) + for i := range items { pkgPathOff := r.uint64() pkgPath := p.stringAt(pkgPathOff) pkgName := p.stringAt(r.uint64()) @@ -218,29 +233,42 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, if pkgPath == "" { pkgPath = path } - pkg := getPackage(pkgPath, pkgName) - if pkg == nil { - errorf("internal error: getPackage returned nil package for %s", pkgPath) - } else if pkg.Name() != pkgName { - errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) - } - if i == 0 && !bundle { - p.localpkg = pkg - } - - p.pkgCache[pkgPathOff] = pkg + items[i].Name = pkgName + items[i].Path = pkgPath + items[i].pathOffset = pkgPathOff // Read index for package. nameIndex := make(map[string]uint64) nSyms := r.uint64() - // In shallow mode we don't expect an index for other packages. - assert(nSyms == 0 || p.localpkg == pkg || p.insert == nil) + // In shallow mode, only the current package (i=0) has an index. + assert(!(shallow && i > 0 && nSyms != 0)) for ; nSyms > 0; nSyms-- { name := p.stringAt(r.uint64()) nameIndex[name] = r.uint64() } - p.pkgIndex[pkg] = nameIndex + items[i].nameIndex = nameIndex + } + + // Request packages all at once from the client, + // enabling a parallel implementation. + if err := getPackages(items); err != nil { + return nil, err // don't wrap this error + } + + // Check the results and complete the index. + pkgList := make([]*types.Package, len(items)) + for i, item := range items { + pkg := item.Pkg + if pkg == nil { + errorf("internal error: getPackages returned nil package for %q", item.Path) + } else if pkg.Path() != item.Path { + errorf("internal error: getPackages returned wrong path %q, want %q", pkg.Path(), item.Path) + } else if pkg.Name() != item.Name { + errorf("internal error: getPackages returned wrong name %s for package %q, want %s", pkg.Name(), item.Path, item.Name) + } + p.pkgCache[item.pathOffset] = pkg + p.pkgIndex[pkg] = item.nameIndex pkgList[i] = pkg } @@ -292,18 +320,25 @@ func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, // Therefore, we defer calling SetConstraint there, and call it here instead // after all types are complete. for _, d := range p.later { - typeparams.SetTypeParamConstraint(d.t, d.constraint) + d.t.SetConstraint(d.constraint) } for _, typ := range p.interfaceList { typ.Complete() } + // Workaround for golang/go#61561. See the doc for instanceList for details. + for _, typ := range p.instanceList { + if iface, _ := typ.Underlying().(*types.Interface); iface != nil { + iface.Complete() + } + } + return pkgs, nil } type setConstraintArgs struct { - t *typeparams.TypeParam + t *types.TypeParam constraint types.Type } @@ -311,8 +346,8 @@ type iimporter struct { version int ipath string - localpkg *types.Package - insert func(pkg *types.Package, name string) // "shallow" mode only + shallow bool + reportf ReportFunc // if non-nil, used to report bugs stringData []byte stringCache map[uint64]string @@ -329,6 +364,12 @@ type iimporter struct { fake fakeFileSet interfaceList []*types.Interface + // Workaround for the go/types bug golang/go#61561: instances produced during + // instantiation may contain incomplete interfaces. Here we only complete the + // underlying type of the instance, which is the most common case but doesn't + // handle parameterized interface literals defined deeper in the type. + instanceList []types.Type // instances for later completion (see golang/go#61561) + // Arguments for calls to SetConstraint that are deferred due to recursive types later []setConstraintArgs @@ -360,13 +401,9 @@ func (p *iimporter) doDecl(pkg *types.Package, name string) { off, ok := p.pkgIndex[pkg][name] if !ok { - // In "shallow" mode, call back to the application to - // find the object and insert it into the package scope. - if p.insert != nil { - assert(pkg != p.localpkg) - p.insert(pkg, name) // "can't fail" - return - } + // In deep mode, the index should be complete. In shallow + // mode, we should have already recursively loaded necessary + // dependencies so the above Lookup succeeds. errorf("%v.%v not in index", pkg, name) } @@ -511,7 +548,7 @@ func (r *importReader) obj(name string) { r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) case 'F', 'G': - var tparams []*typeparams.TypeParam + var tparams []*types.TypeParam if tag == 'G' { tparams = r.tparamList() } @@ -528,7 +565,7 @@ func (r *importReader) obj(name string) { r.declare(obj) if tag == 'U' { tparams := r.tparamList() - typeparams.SetForNamed(named, tparams) + named.SetTypeParams(tparams) } underlying := r.p.typAt(r.uint64(), named).Underlying() @@ -545,12 +582,12 @@ func (r *importReader) obj(name string) { // typeparams being used in the method sig/body). base := baseType(recv.Type()) assert(base != nil) - targs := typeparams.NamedTypeArgs(base) - var rparams []*typeparams.TypeParam + targs := base.TypeArgs() + var rparams []*types.TypeParam if targs.Len() > 0 { - rparams = make([]*typeparams.TypeParam, targs.Len()) + rparams = make([]*types.TypeParam, targs.Len()) for i := range rparams { - rparams[i] = targs.At(i).(*typeparams.TypeParam) + rparams[i] = targs.At(i).(*types.TypeParam) } } msig := r.signature(recv, rparams, nil) @@ -568,7 +605,7 @@ func (r *importReader) obj(name string) { } name0 := tparamName(name) tn := types.NewTypeName(pos, r.currPkg, name0, nil) - t := typeparams.NewTypeParam(tn, nil) + t := types.NewTypeParam(tn, nil) // To handle recursive references to the typeparam within its // bound, save the partial type in tparamIndex before reading the bounds. @@ -584,7 +621,7 @@ func (r *importReader) obj(name string) { if iface == nil { errorf("non-interface constraint marked implicit") } - typeparams.MarkImplicit(iface) + iface.MarkImplicit() } // The constraint type may not be complete, if we // are in the middle of a type recursion involving type @@ -733,7 +770,8 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) { } func (r *importReader) pos() token.Pos { - if r.p.insert != nil { // shallow mode + if r.p.shallow { + // precise offsets are encoded only in shallow mode return r.posv2() } if r.p.version >= iexportVersionPosCol { @@ -834,13 +872,28 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { fields := make([]*types.Var, r.uint64()) tags := make([]string, len(fields)) for i := range fields { + var field *types.Var + if r.p.shallow { + field, _ = r.objectPathObject().(*types.Var) + } + fpos := r.pos() fname := r.ident() ftyp := r.typ() emb := r.bool() tag := r.string() - fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb) + // Either this is not a shallow import, the field is local, or the + // encoded objectPath failed to produce an object (a bug). + // + // Even in this last, buggy case, fall back on creating a new field. As + // discussed in iexport.go, this is not correct, but mostly works and is + // preferable to failing (for now at least). + if field == nil { + field = types.NewField(fpos, r.currPkg, fname, ftyp, emb) + } + + fields[i] = field tags[i] = tag } return types.NewStruct(fields, tags) @@ -856,6 +909,11 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { methods := make([]*types.Func, r.uint64()) for i := range methods { + var method *types.Func + if r.p.shallow { + method, _ = r.objectPathObject().(*types.Func) + } + mpos := r.pos() mname := r.ident() @@ -865,9 +923,12 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { if base != nil { recv = types.NewVar(token.NoPos, r.currPkg, "", base) } - msig := r.signature(recv, nil, nil) - methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig) + + if method == nil { + method = types.NewFunc(mpos, r.currPkg, mname, msig) + } + methods[i] = method } typ := newInterface(methods, embeddeds) @@ -904,18 +965,21 @@ func (r *importReader) doType(base *types.Named) (res types.Type) { // The imported instantiated type doesn't include any methods, so // we must always use the methods of the base (orig) type. // TODO provide a non-nil *Environment - t, _ := typeparams.Instantiate(nil, baseType, targs, false) + t, _ := types.Instantiate(nil, baseType, targs, false) + + // Workaround for golang/go#61561. See the doc for instanceList for details. + r.p.instanceList = append(r.p.instanceList, t) return t case unionType: if r.p.version < iexportVersionGenerics { errorf("unexpected instantiation type") } - terms := make([]*typeparams.Term, r.uint64()) + terms := make([]*types.Term, r.uint64()) for i := range terms { - terms[i] = typeparams.NewTerm(r.bool(), r.typ()) + terms[i] = types.NewTerm(r.bool(), r.typ()) } - return typeparams.NewUnion(terms) + return types.NewUnion(terms) } } @@ -923,23 +987,43 @@ func (r *importReader) kind() itag { return itag(r.uint64()) } -func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature { +// objectPathObject is the inverse of exportWriter.objectPath. +// +// In shallow mode, certain fields and methods may need to be looked up in an +// imported package. See the doc for exportWriter.objectPath for a full +// explanation. +func (r *importReader) objectPathObject() types.Object { + objPath := objectpath.Path(r.string()) + if objPath == "" { + return nil + } + pkg := r.pkg() + obj, err := objectpath.Object(pkg, objPath) + if err != nil { + if r.p.reportf != nil { + r.p.reportf("failed to find object for objectPath %q: %v", objPath, err) + } + } + return obj +} + +func (r *importReader) signature(recv *types.Var, rparams []*types.TypeParam, tparams []*types.TypeParam) *types.Signature { params := r.paramList() results := r.paramList() variadic := params.Len() > 0 && r.bool() - return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic) + return types.NewSignatureType(recv, rparams, tparams, params, results, variadic) } -func (r *importReader) tparamList() []*typeparams.TypeParam { +func (r *importReader) tparamList() []*types.TypeParam { n := r.uint64() if n == 0 { return nil } - xs := make([]*typeparams.TypeParam, n) + xs := make([]*types.TypeParam, n) for i := range xs { // Note: the standard library importer is tolerant of nil types here, // though would panic in SetTypeParams. - xs[i] = r.typ().(*typeparams.TypeParam) + xs[i] = r.typ().(*types.TypeParam) } return xs } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go index 34fc783f8..b977435f6 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go @@ -10,6 +10,7 @@ package gcimporter import ( + "fmt" "go/token" "go/types" "sort" @@ -63,6 +64,14 @@ type typeInfo struct { } func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { + if !debug { + defer func() { + if x := recover(); x != nil { + err = fmt.Errorf("internal error in importing %q (%v); please report an issue", path, x) + } + }() + } + s := string(data) s = s[:strings.LastIndex(s, "\n$$\n")] input := pkgbits.NewPkgDecoder(path, s) diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go index d50551693..55312522d 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -8,10 +8,13 @@ package gocommand import ( "bytes" "context" + "errors" "fmt" "io" "log" "os" + "os/exec" + "reflect" "regexp" "runtime" "strconv" @@ -19,9 +22,10 @@ import ( "sync" "time" - exec "golang.org/x/sys/execabs" - "golang.org/x/tools/internal/event" + "golang.org/x/tools/internal/event/keys" + "golang.org/x/tools/internal/event/label" + "golang.org/x/tools/internal/event/tag" ) // An Runner will run go command invocations and serialize @@ -51,9 +55,19 @@ func (runner *Runner) initialize() { // 1.14: go: updating go.mod: existing contents have changed since last read var modConcurrencyError = regexp.MustCompile(`go:.*go.mod.*contents have changed`) +// verb is an event label for the go command verb. +var verb = keys.NewString("verb", "go command verb") + +func invLabels(inv Invocation) []label.Label { + return []label.Label{verb.Of(inv.Verb), tag.Directory.Of(inv.WorkingDir)} +} + // Run is a convenience wrapper around RunRaw. // It returns only stdout and a "friendly" error. func (runner *Runner) Run(ctx context.Context, inv Invocation) (*bytes.Buffer, error) { + ctx, done := event.Start(ctx, "gocommand.Runner.Run", invLabels(inv)...) + defer done() + stdout, _, friendly, _ := runner.RunRaw(ctx, inv) return stdout, friendly } @@ -61,13 +75,19 @@ func (runner *Runner) Run(ctx context.Context, inv Invocation) (*bytes.Buffer, e // RunPiped runs the invocation serially, always waiting for any concurrent // invocations to complete first. func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) error { + ctx, done := event.Start(ctx, "gocommand.Runner.RunPiped", invLabels(inv)...) + defer done() + _, err := runner.runPiped(ctx, inv, stdout, stderr) return err } // RunRaw runs the invocation, serializing requests only if they fight over // go.mod changes. +// Postcondition: both error results have same nilness. func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { + ctx, done := event.Start(ctx, "gocommand.Runner.RunRaw", invLabels(inv)...) + defer done() // Make sure the runner is always initialized. runner.initialize() @@ -75,23 +95,24 @@ func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv) // If we encounter a load concurrency error, we need to retry serially. - if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) { - return stdout, stderr, friendlyErr, err + if friendlyErr != nil && modConcurrencyError.MatchString(friendlyErr.Error()) { + event.Error(ctx, "Load concurrency error, will retry serially", err) + + // Run serially by calling runPiped. + stdout.Reset() + stderr.Reset() + friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr) } - event.Error(ctx, "Load concurrency error, will retry serially", err) - // Run serially by calling runPiped. - stdout.Reset() - stderr.Reset() - friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr) return stdout, stderr, friendlyErr, err } +// Postcondition: both error results have same nilness. func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { // Wait for 1 worker to become available. select { case <-ctx.Done(): - return nil, nil, nil, ctx.Err() + return nil, nil, ctx.Err(), ctx.Err() case runner.inFlight <- struct{}{}: defer func() { <-runner.inFlight }() } @@ -101,6 +122,7 @@ func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes return stdout, stderr, friendlyErr, err } +// Postcondition: both error results have same nilness. func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) { // Make sure the runner is always initialized. runner.initialize() @@ -109,7 +131,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde // runPiped commands. select { case <-ctx.Done(): - return nil, ctx.Err() + return ctx.Err(), ctx.Err() case runner.serialized <- struct{}{}: defer func() { <-runner.serialized }() } @@ -119,7 +141,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde for i := 0; i < maxInFlight; i++ { select { case <-ctx.Done(): - return nil, ctx.Err() + return ctx.Err(), ctx.Err() case runner.inFlight <- struct{}{}: // Make sure we always "return" any workers we took. defer func() { <-runner.inFlight }() @@ -152,6 +174,7 @@ type Invocation struct { Logf func(format string, args ...interface{}) } +// Postcondition: both error results have same nilness. func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) { rawError = i.run(ctx, stdout, stderr) if rawError != nil { @@ -215,6 +238,18 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { cmd := exec.Command("go", goArgs...) cmd.Stdout = stdout cmd.Stderr = stderr + + // cmd.WaitDelay was added only in go1.20 (see #50436). + if waitDelay := reflect.ValueOf(cmd).Elem().FieldByName("WaitDelay"); waitDelay.IsValid() { + // https://go.dev/issue/59541: don't wait forever copying stderr + // after the command has exited. + // After CL 484741 we copy stdout manually, so we we'll stop reading that as + // soon as ctx is done. However, we also don't want to wait around forever + // for stderr. Give a much-longer-than-reasonable delay and then assume that + // something has wedged in the kernel or runtime. + waitDelay.Set(reflect.ValueOf(30 * time.Second)) + } + // On darwin the cwd gets resolved to the real path, which breaks anything that // expects the working directory to keep the original path, including the // go command when dealing with modules. @@ -229,6 +264,7 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { cmd.Env = append(cmd.Env, "PWD="+i.WorkingDir) cmd.Dir = i.WorkingDir } + defer func(start time.Time) { log("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) return runCmdContext(ctx, cmd) @@ -242,10 +278,85 @@ var DebugHangingGoCommands = false // runCmdContext is like exec.CommandContext except it sends os.Interrupt // before os.Kill. -func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { - if err := cmd.Start(); err != nil { +func runCmdContext(ctx context.Context, cmd *exec.Cmd) (err error) { + // If cmd.Stdout is not an *os.File, the exec package will create a pipe and + // copy it to the Writer in a goroutine until the process has finished and + // either the pipe reaches EOF or command's WaitDelay expires. + // + // However, the output from 'go list' can be quite large, and we don't want to + // keep reading (and allocating buffers) if we've already decided we don't + // care about the output. We don't want to wait for the process to finish, and + // we don't wait to wait for the WaitDelay to expire either. + // + // Instead, if cmd.Stdout requires a copying goroutine we explicitly replace + // it with a pipe (which is an *os.File), which we can close in order to stop + // copying output as soon as we realize we don't care about it. + var stdoutW *os.File + if cmd.Stdout != nil { + if _, ok := cmd.Stdout.(*os.File); !ok { + var stdoutR *os.File + stdoutR, stdoutW, err = os.Pipe() + if err != nil { + return err + } + prevStdout := cmd.Stdout + cmd.Stdout = stdoutW + + stdoutErr := make(chan error, 1) + go func() { + _, err := io.Copy(prevStdout, stdoutR) + if err != nil { + err = fmt.Errorf("copying stdout: %w", err) + } + stdoutErr <- err + }() + defer func() { + // We started a goroutine to copy a stdout pipe. + // Wait for it to finish, or terminate it if need be. + var err2 error + select { + case err2 = <-stdoutErr: + stdoutR.Close() + case <-ctx.Done(): + stdoutR.Close() + // Per https://pkg.go.dev/os#File.Close, the call to stdoutR.Close + // should cause the Read call in io.Copy to unblock and return + // immediately, but we still need to receive from stdoutErr to confirm + // that it has happened. + <-stdoutErr + err2 = ctx.Err() + } + if err == nil { + err = err2 + } + }() + + // Per https://pkg.go.dev/os/exec#Cmd, “If Stdout and Stderr are the + // same writer, and have a type that can be compared with ==, at most + // one goroutine at a time will call Write.” + // + // Since we're starting a goroutine that writes to cmd.Stdout, we must + // also update cmd.Stderr so that it still holds. + func() { + defer func() { recover() }() + if cmd.Stderr == prevStdout { + cmd.Stderr = cmd.Stdout + } + }() + } + } + + err = cmd.Start() + if stdoutW != nil { + // The child process has inherited the pipe file, + // so close the copy held in this process. + stdoutW.Close() + stdoutW = nil + } + if err != nil { return err } + resChan := make(chan error, 1) go func() { resChan <- cmd.Wait() @@ -253,11 +364,14 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { // If we're interested in debugging hanging Go commands, stop waiting after a // minute and panic with interesting information. - if DebugHangingGoCommands { + debug := DebugHangingGoCommands + if debug { + timer := time.NewTimer(1 * time.Minute) + defer timer.Stop() select { case err := <-resChan: return err - case <-time.After(1 * time.Minute): + case <-timer.C: HandleHangingGoCommand(cmd.Process) case <-ctx.Done(): } @@ -270,30 +384,25 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { } // Cancelled. Interrupt and see if it ends voluntarily. - cmd.Process.Signal(os.Interrupt) - select { - case err := <-resChan: - return err - case <-time.After(time.Second): + if err := cmd.Process.Signal(os.Interrupt); err == nil { + // (We used to wait only 1s but this proved + // fragile on loaded builder machines.) + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + select { + case err := <-resChan: + return err + case <-timer.C: + } } // Didn't shut down in response to interrupt. Kill it hard. // TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT // on certain platforms, such as unix. - if err := cmd.Process.Kill(); err != nil && DebugHangingGoCommands { - // Don't panic here as this reliably fails on windows with EINVAL. + if err := cmd.Process.Kill(); err != nil && !errors.Is(err, os.ErrProcessDone) && debug { log.Printf("error killing the Go command: %v", err) } - // See above: don't wait indefinitely if we're debugging hanging Go commands. - if DebugHangingGoCommands { - select { - case err := <-resChan: - return err - case <-time.After(10 * time.Second): // a shorter wait as resChan should return quickly following Kill - HandleHangingGoCommand(cmd.Process) - } - } return <-resChan } diff --git a/vendor/golang.org/x/tools/internal/gocommand/version.go b/vendor/golang.org/x/tools/internal/gocommand/version.go index 307a76d47..446c5846a 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/version.go +++ b/vendor/golang.org/x/tools/internal/gocommand/version.go @@ -23,21 +23,11 @@ import ( func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) { inv.Verb = "list" inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`} - inv.Env = append(append([]string{}, inv.Env...), "GO111MODULE=off") - // Unset any unneeded flags, and remove them from BuildFlags, if they're - // present. - inv.ModFile = "" + inv.BuildFlags = nil // This is not a build command. inv.ModFlag = "" - var buildFlags []string - for _, flag := range inv.BuildFlags { - // Flags can be prefixed by one or two dashes. - f := strings.TrimPrefix(strings.TrimPrefix(flag, "-"), "-") - if strings.HasPrefix(f, "mod=") || strings.HasPrefix(f, "modfile=") { - continue - } - buildFlags = append(buildFlags, flag) - } - inv.BuildFlags = buildFlags + inv.ModFile = "" + inv.Env = append(inv.Env[:len(inv.Env):len(inv.Env)], "GO111MODULE=off") + stdoutBytes, err := r.Run(ctx, inv) if err != nil { return 0, err diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go index 168405322..52f74e643 100644 --- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go +++ b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go @@ -9,15 +9,12 @@ package gopathwalk import ( "bufio" "bytes" - "fmt" - "io/ioutil" + "io/fs" "log" "os" "path/filepath" "strings" "time" - - "golang.org/x/tools/internal/fastwalk" ) // Options controls the behavior of a Walk call. @@ -47,21 +44,18 @@ type Root struct { } // Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. -// For each package found, add will be called (concurrently) with the absolute +// For each package found, add will be called with the absolute // paths of the containing source directory and the package directory. -// add will be called concurrently. func Walk(roots []Root, add func(root Root, dir string), opts Options) { WalkSkip(roots, add, func(Root, string) bool { return false }, opts) } // WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. -// For each package found, add will be called (concurrently) with the absolute +// For each package found, add will be called with the absolute // paths of the containing source directory and the package directory. -// For each directory that will be scanned, skip will be called (concurrently) +// For each directory that will be scanned, skip will be called // with the absolute paths of the containing source directory and the directory. // If skip returns false on a directory it will be processed. -// add will be called concurrently. -// skip will be called concurrently. func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { for _, root := range roots { walkDir(root, add, skip, opts) @@ -78,21 +72,36 @@ func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) } start := time.Now() if opts.Logf != nil { - opts.Logf("gopathwalk: scanning %s", root.Path) + opts.Logf("scanning %s", root.Path) } + w := &walker{ - root: root, - add: add, - skip: skip, - opts: opts, + root: root, + add: add, + skip: skip, + opts: opts, + added: make(map[string]bool), } w.init() - if err := fastwalk.Walk(root.Path, w.walk); err != nil { - log.Printf("gopathwalk: scanning directory %v: %v", root.Path, err) + + // Add a trailing path separator to cause filepath.WalkDir to traverse symlinks. + path := root.Path + if len(path) == 0 { + path = "." + string(filepath.Separator) + } else if !os.IsPathSeparator(path[len(path)-1]) { + path = path + string(filepath.Separator) + } + + if err := filepath.WalkDir(path, w.walk); err != nil { + logf := opts.Logf + if logf == nil { + logf = log.Printf + } + logf("scanning directory %v: %v", root.Path, err) } if opts.Logf != nil { - opts.Logf("gopathwalk: scanned %s in %v", root.Path, time.Since(start)) + opts.Logf("scanned %s in %v", root.Path, time.Since(start)) } } @@ -103,7 +112,10 @@ type walker struct { skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. opts Options // Options passed to Walk by the user. - ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. + pathSymlinks []os.FileInfo + ignoredDirs []string + + added map[string]bool } // init initializes the walker based on its Options @@ -119,13 +131,9 @@ func (w *walker) init() { for _, p := range ignoredPaths { full := filepath.Join(w.root.Path, p) - if fi, err := os.Stat(full); err == nil { - w.ignoredDirs = append(w.ignoredDirs, fi) - if w.opts.Logf != nil { - w.opts.Logf("Directory added to ignore list: %s", full) - } - } else if w.opts.Logf != nil { - w.opts.Logf("Error statting ignored directory: %v", err) + w.ignoredDirs = append(w.ignoredDirs, full) + if w.opts.Logf != nil { + w.opts.Logf("Directory added to ignore list: %s", full) } } } @@ -135,7 +143,7 @@ func (w *walker) init() { // The provided path is one of the $GOPATH entries with "src" appended. func (w *walker) getIgnoredDirs(path string) []string { file := filepath.Join(path, ".goimportsignore") - slurp, err := ioutil.ReadFile(file) + slurp, err := os.ReadFile(file) if w.opts.Logf != nil { if err != nil { w.opts.Logf("%v", err) @@ -160,9 +168,9 @@ func (w *walker) getIgnoredDirs(path string) []string { } // shouldSkipDir reports whether the file should be skipped or not. -func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { +func (w *walker) shouldSkipDir(dir string) bool { for _, ignoredDir := range w.ignoredDirs { - if os.SameFile(fi, ignoredDir) { + if dir == ignoredDir { return true } } @@ -174,81 +182,150 @@ func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { } // walk walks through the given path. -func (w *walker) walk(path string, typ os.FileMode) error { - if typ.IsRegular() { +// +// Errors are logged if w.opts.Logf is non-nil, but otherwise ignored: +// walk returns only nil or fs.SkipDir. +func (w *walker) walk(path string, d fs.DirEntry, err error) error { + if err != nil { + // We have no way to report errors back through Walk or WalkSkip, + // so just log and ignore them. + if w.opts.Logf != nil { + w.opts.Logf("%v", err) + } + if d == nil { + // Nothing more to do: the error prevents us from knowing + // what path even represents. + return nil + } + } + + if d.Type().IsRegular() { + if !strings.HasSuffix(path, ".go") { + return nil + } + dir := filepath.Dir(path) if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) { // Doesn't make sense to have regular files // directly in your $GOPATH/src or $GOROOT/src. - return fastwalk.ErrSkipFiles - } - if !strings.HasSuffix(path, ".go") { return nil } - w.add(w.root, dir) - return fastwalk.ErrSkipFiles + if !w.added[dir] { + w.add(w.root, dir) + w.added[dir] = true + } + return nil } - if typ == os.ModeDir { + + if d.IsDir() { base := filepath.Base(path) if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" || (w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") || (!w.opts.ModulesEnabled && base == "node_modules") { - return filepath.SkipDir + return fs.SkipDir } - fi, err := os.Lstat(path) - if err == nil && w.shouldSkipDir(fi, path) { - return filepath.SkipDir + if w.shouldSkipDir(path) { + return fs.SkipDir } return nil } - if typ == os.ModeSymlink { - base := filepath.Base(path) - if strings.HasPrefix(base, ".#") { - // Emacs noise. - return nil + + if d.Type()&os.ModeSymlink != 0 { + // TODO(bcmills): 'go list all' itself ignores symlinks within GOROOT/src + // and GOPATH/src. Do we really need to traverse them here? If so, why? + + fi, err := os.Stat(path) + if err != nil || !fi.IsDir() { + // Not a directory. Just walk the file (or broken link) and be done. + return w.walk(path, fs.FileInfoToDirEntry(fi), err) } - if w.shouldTraverse(path) { - return fastwalk.ErrTraverseLink + + // Avoid walking symlink cycles: if we have already followed a symlink to + // this directory as a parent of itself, don't follow it again. + // + // This doesn't catch the first time through a cycle, but it also minimizes + // the number of extra stat calls we make if we *don't* encounter a cycle. + // Since we don't actually expect to encounter symlink cycles in practice, + // this seems like the right tradeoff. + for _, parent := range w.pathSymlinks { + if os.SameFile(fi, parent) { + return nil + } } - } - return nil -} -// shouldTraverse reports whether the symlink fi, found in dir, -// should be followed. It makes sure symlinks were never visited -// before to avoid symlink loops. -func (w *walker) shouldTraverse(path string) bool { - ts, err := os.Stat(path) - if err != nil { - fmt.Fprintln(os.Stderr, err) - return false - } - if !ts.IsDir() { - return false - } - if w.shouldSkipDir(ts, filepath.Dir(path)) { - return false - } - // Check for symlink loops by statting each directory component - // and seeing if any are the same file as ts. - for { - parent := filepath.Dir(path) - if parent == path { - // Made it to the root without seeing a cycle. - // Use this symlink. - return true + w.pathSymlinks = append(w.pathSymlinks, fi) + defer func() { + w.pathSymlinks = w.pathSymlinks[:len(w.pathSymlinks)-1] + }() + + // On some platforms the OS (or the Go os package) sometimes fails to + // resolve directory symlinks before a trailing slash + // (even though POSIX requires it to do so). + // + // On macOS that failure may be caused by a known libc/kernel bug; + // see https://go.dev/issue/59586. + // + // On Windows before Go 1.21, it may be caused by a bug in + // os.Lstat (fixed in https://go.dev/cl/463177). + // + // Since we need to handle this explicitly on broken platforms anyway, + // it is simplest to just always do that and not rely on POSIX pathname + // resolution to walk the directory (such as by calling WalkDir with + // a trailing slash appended to the path). + // + // Instead, we make a sequence of walk calls — directly and through + // recursive calls to filepath.WalkDir — simulating what WalkDir would do + // if the symlink were a regular directory. + + // First we call walk on the path as a directory + // (instead of a symlink). + err = w.walk(path, fs.FileInfoToDirEntry(fi), nil) + if err == fs.SkipDir { + return nil + } else if err != nil { + // This should be impossible, but handle it anyway in case + // walk is changed to return other errors. + return err } - parentInfo, err := os.Stat(parent) + + // Now read the directory and walk its entries. + ents, err := os.ReadDir(path) if err != nil { - return false + // Report the ReadDir error, as filepath.WalkDir would do. + err = w.walk(path, fs.FileInfoToDirEntry(fi), err) + if err == fs.SkipDir { + return nil + } else if err != nil { + return err // Again, should be impossible. + } + // Fall through and iterate over whatever entries we did manage to get. } - if os.SameFile(ts, parentInfo) { - // Cycle. Don't traverse. - return false + + for _, d := range ents { + nextPath := filepath.Join(path, d.Name()) + if d.IsDir() { + // We want to walk the whole directory tree rooted at nextPath, + // not just the single entry for the directory. + err := filepath.WalkDir(nextPath, w.walk) + if err != nil && w.opts.Logf != nil { + w.opts.Logf("%v", err) + } + } else { + err := w.walk(nextPath, d, nil) + if err == fs.SkipDir { + // Skip the rest of the entries in the parent directory of nextPath + // (that is, path itself). + break + } else if err != nil { + return err // Again, should be impossible. + } + } } - path = parent + return nil } + // Not a file, regular directory, or symlink; skip. + return nil } diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go index 642a5ac2d..dd369c072 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -13,6 +13,7 @@ import ( "go/build" "go/parser" "go/token" + "io/fs" "io/ioutil" "os" "path" @@ -26,6 +27,7 @@ import ( "unicode/utf8" "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/gopathwalk" ) @@ -106,7 +108,7 @@ func parseOtherFiles(fset *token.FileSet, srcDir, filename string) []*ast.File { considerTests := strings.HasSuffix(filename, "_test.go") fileBase := filepath.Base(filename) - packageFileInfos, err := ioutil.ReadDir(srcDir) + packageFileInfos, err := os.ReadDir(srcDir) if err != nil { return nil } @@ -252,7 +254,7 @@ type pass struct { otherFiles []*ast.File // sibling files. // Intermediate state, generated by load. - existingImports map[string]*ImportInfo + existingImports map[string][]*ImportInfo allRefs references missingRefs references @@ -317,7 +319,7 @@ func (p *pass) importIdentifier(imp *ImportInfo) string { func (p *pass) load() ([]*ImportFix, bool) { p.knownPackages = map[string]*packageInfo{} p.missingRefs = references{} - p.existingImports = map[string]*ImportInfo{} + p.existingImports = map[string][]*ImportInfo{} // Load basic information about the file in question. p.allRefs = collectReferences(p.f) @@ -348,7 +350,7 @@ func (p *pass) load() ([]*ImportFix, bool) { } } for _, imp := range imports { - p.existingImports[p.importIdentifier(imp)] = imp + p.existingImports[p.importIdentifier(imp)] = append(p.existingImports[p.importIdentifier(imp)], imp) } // Find missing references. @@ -387,36 +389,45 @@ func (p *pass) fix() ([]*ImportFix, bool) { // Found everything, or giving up. Add the new imports and remove any unused. var fixes []*ImportFix - for _, imp := range p.existingImports { - // We deliberately ignore globals here, because we can't be sure - // they're in the same package. People do things like put multiple - // main packages in the same directory, and we don't want to - // remove imports if they happen to have the same name as a var in - // a different package. - if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { - fixes = append(fixes, &ImportFix{ - StmtInfo: *imp, - IdentName: p.importIdentifier(imp), - FixType: DeleteImport, - }) - continue - } + for _, identifierImports := range p.existingImports { + for _, imp := range identifierImports { + // We deliberately ignore globals here, because we can't be sure + // they're in the same package. People do things like put multiple + // main packages in the same directory, and we don't want to + // remove imports if they happen to have the same name as a var in + // a different package. + if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { + fixes = append(fixes, &ImportFix{ + StmtInfo: *imp, + IdentName: p.importIdentifier(imp), + FixType: DeleteImport, + }) + continue + } - // An existing import may need to update its import name to be correct. - if name := p.importSpecName(imp); name != imp.Name { - fixes = append(fixes, &ImportFix{ - StmtInfo: ImportInfo{ - Name: name, - ImportPath: imp.ImportPath, - }, - IdentName: p.importIdentifier(imp), - FixType: SetImportName, - }) + // An existing import may need to update its import name to be correct. + if name := p.importSpecName(imp); name != imp.Name { + fixes = append(fixes, &ImportFix{ + StmtInfo: ImportInfo{ + Name: name, + ImportPath: imp.ImportPath, + }, + IdentName: p.importIdentifier(imp), + FixType: SetImportName, + }) + } } } + // Collecting fixes involved map iteration, so sort for stability. See + // golang/go#59976. + sortFixes(fixes) + // collect selected fixes in a separate slice, so that it can be sorted + // separately. Note that these fixes must occur after fixes to existing + // imports. TODO(rfindley): figure out why. + var selectedFixes []*ImportFix for _, imp := range selected { - fixes = append(fixes, &ImportFix{ + selectedFixes = append(selectedFixes, &ImportFix{ StmtInfo: ImportInfo{ Name: p.importSpecName(imp), ImportPath: imp.ImportPath, @@ -425,8 +436,25 @@ func (p *pass) fix() ([]*ImportFix, bool) { FixType: AddImport, }) } + sortFixes(selectedFixes) - return fixes, true + return append(fixes, selectedFixes...), true +} + +func sortFixes(fixes []*ImportFix) { + sort.Slice(fixes, func(i, j int) bool { + fi, fj := fixes[i], fixes[j] + if fi.StmtInfo.ImportPath != fj.StmtInfo.ImportPath { + return fi.StmtInfo.ImportPath < fj.StmtInfo.ImportPath + } + if fi.StmtInfo.Name != fj.StmtInfo.Name { + return fi.StmtInfo.Name < fj.StmtInfo.Name + } + if fi.IdentName != fj.IdentName { + return fi.IdentName < fj.IdentName + } + return fi.FixType < fj.FixType + }) } // importSpecName gets the import name of imp in the import spec. @@ -519,7 +547,7 @@ func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) { var fixImports = fixImportsDefault func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error { - fixes, err := getFixes(fset, f, filename, env) + fixes, err := getFixes(context.Background(), fset, f, filename, env) if err != nil { return err } @@ -529,7 +557,7 @@ func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *P // getFixes gets the import fixes that need to be made to f in order to fix the imports. // It does not modify the ast. -func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { +func getFixes(ctx context.Context, fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { abs, err := filepath.Abs(filename) if err != nil { return nil, err @@ -583,7 +611,7 @@ func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv // Go look for candidates in $GOPATH, etc. We don't necessarily load // the real exports of sibling imports, so keep assuming their contents. - if err := addExternalCandidates(p, p.missingRefs, filename); err != nil { + if err := addExternalCandidates(ctx, p, p.missingRefs, filename); err != nil { return nil, err } @@ -1031,7 +1059,10 @@ type scanCallback struct { exportsLoaded func(pkg *pkg, exports []string) } -func addExternalCandidates(pass *pass, refs references, filename string) error { +func addExternalCandidates(ctx context.Context, pass *pass, refs references, filename string) error { + ctx, done := event.Start(ctx, "imports.addExternalCandidates") + defer done() + var mu sync.Mutex found := make(map[string][]pkgDistance) callback := &scanCallback{ @@ -1441,11 +1472,11 @@ func VendorlessPath(ipath string) string { func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) { // Look for non-test, buildable .go files which could provide exports. - all, err := ioutil.ReadDir(dir) + all, err := os.ReadDir(dir) if err != nil { return "", nil, err } - var files []os.FileInfo + var files []fs.DirEntry for _, fi := range all { name := fi.Name() if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) { diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go index 95a88383a..58e637b90 100644 --- a/vendor/golang.org/x/tools/internal/imports/imports.go +++ b/vendor/golang.org/x/tools/internal/imports/imports.go @@ -11,6 +11,7 @@ package imports import ( "bufio" "bytes" + "context" "fmt" "go/ast" "go/format" @@ -23,6 +24,7 @@ import ( "strings" "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/internal/event" ) // Options is golang.org/x/tools/imports.Options with extra internal-only options. @@ -66,14 +68,17 @@ func Process(filename string, src []byte, opt *Options) (formatted []byte, err e // // Note that filename's directory influences which imports can be chosen, // so it is important that filename be accurate. -func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { +func FixImports(ctx context.Context, filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { + ctx, done := event.Start(ctx, "imports.FixImports") + defer done() + fileSet := token.NewFileSet() file, _, err := parse(fileSet, filename, src, opt) if err != nil { return nil, err } - return getFixes(fileSet, file, filename, opt.Env) + return getFixes(ctx, fileSet, file, filename, opt.Env) } // ApplyFixes applies all of the fixes to the file and formats it. extraMode diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go index 7d99d04ca..5f4d435d3 100644 --- a/vendor/golang.org/x/tools/internal/imports/mod.go +++ b/vendor/golang.org/x/tools/internal/imports/mod.go @@ -9,7 +9,6 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "os" "path" "path/filepath" @@ -19,6 +18,7 @@ import ( "strings" "golang.org/x/mod/module" + "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/gopathwalk" ) @@ -37,7 +37,7 @@ type ModuleResolver struct { mains []*gocommand.ModuleJSON mainByDir map[string]*gocommand.ModuleJSON modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path... - modsByDir []*gocommand.ModuleJSON // ...or Dir. + modsByDir []*gocommand.ModuleJSON // ...or number of path components in their Dir. // moduleCacheCache stores information about the module cache. moduleCacheCache *dirInfoCache @@ -123,7 +123,7 @@ func (r *ModuleResolver) init() error { }) sort.Slice(r.modsByDir, func(i, j int) bool { count := func(x int) int { - return strings.Count(r.modsByDir[x].Dir, "/") + return strings.Count(r.modsByDir[x].Dir, string(filepath.Separator)) } return count(j) < count(i) // descending order }) @@ -264,7 +264,7 @@ func (r *ModuleResolver) findPackage(importPath string) (*gocommand.ModuleJSON, } // Not cached. Read the filesystem. - pkgFiles, err := ioutil.ReadDir(pkgDir) + pkgFiles, err := os.ReadDir(pkgDir) if err != nil { continue } @@ -327,6 +327,10 @@ func (r *ModuleResolver) findModuleByDir(dir string) *gocommand.ModuleJSON { // - in /vendor/ in -mod=vendor mode. // - nested module? Dunno. // Rumor has it that replace targets cannot contain other replace targets. + // + // Note that it is critical here that modsByDir is sorted to have deeper dirs + // first. This ensures that findModuleByDir finds the innermost module. + // See also golang/go#56291. for _, m := range r.modsByDir { if !strings.HasPrefix(dir, m.Dir) { continue @@ -365,7 +369,7 @@ func (r *ModuleResolver) dirIsNestedModule(dir string, mod *gocommand.ModuleJSON func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) { readModName := func(modFile string) string { - modBytes, err := ioutil.ReadFile(modFile) + modBytes, err := os.ReadFile(modFile) if err != nil { return "" } @@ -424,6 +428,9 @@ func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) ( } func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error { + ctx, done := event.Start(ctx, "imports.ModuleResolver.scan") + defer done() + if err := r.init(); err != nil { return err } diff --git a/vendor/golang.org/x/tools/internal/imports/mod_cache.go b/vendor/golang.org/x/tools/internal/imports/mod_cache.go index 18dada495..45690abbb 100644 --- a/vendor/golang.org/x/tools/internal/imports/mod_cache.go +++ b/vendor/golang.org/x/tools/internal/imports/mod_cache.go @@ -12,7 +12,7 @@ import ( "golang.org/x/tools/internal/gopathwalk" ) -// To find packages to import, the resolver needs to know about all of the +// To find packages to import, the resolver needs to know about all of // the packages that could be imported. This includes packages that are // already in modules that are in (1) the current module, (2) replace targets, // and (3) packages in the module cache. Packages in (1) and (2) may change over diff --git a/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/vendor/golang.org/x/tools/internal/imports/zstdlib.go index 31a75949c..9f992c2be 100644 --- a/vendor/golang.org/x/tools/internal/imports/zstdlib.go +++ b/vendor/golang.org/x/tools/internal/imports/zstdlib.go @@ -93,6 +93,7 @@ var stdlib = map[string][]string{ "Compare", "Contains", "ContainsAny", + "ContainsFunc", "ContainsRune", "Count", "Cut", @@ -147,6 +148,11 @@ var stdlib = map[string][]string{ "TrimSpace", "TrimSuffix", }, + "cmp": { + "Compare", + "Less", + "Ordered", + }, "compress/bzip2": { "NewReader", "StructuralError", @@ -228,6 +234,7 @@ var stdlib = map[string][]string{ "Ring", }, "context": { + "AfterFunc", "Background", "CancelCauseFunc", "CancelFunc", @@ -239,8 +246,11 @@ var stdlib = map[string][]string{ "WithCancel", "WithCancelCause", "WithDeadline", + "WithDeadlineCause", "WithTimeout", + "WithTimeoutCause", "WithValue", + "WithoutCancel", }, "crypto": { "BLAKE2b_256", @@ -445,6 +455,7 @@ var stdlib = map[string][]string{ "XORBytes", }, "crypto/tls": { + "AlertError", "Certificate", "CertificateRequestInfo", "CertificateVerificationError", @@ -476,6 +487,7 @@ var stdlib = map[string][]string{ "LoadX509KeyPair", "NewLRUClientSessionCache", "NewListener", + "NewResumptionState", "NoClientCert", "PKCS1WithSHA1", "PKCS1WithSHA256", @@ -484,6 +496,27 @@ var stdlib = map[string][]string{ "PSSWithSHA256", "PSSWithSHA384", "PSSWithSHA512", + "ParseSessionState", + "QUICClient", + "QUICConfig", + "QUICConn", + "QUICEncryptionLevel", + "QUICEncryptionLevelApplication", + "QUICEncryptionLevelEarly", + "QUICEncryptionLevelHandshake", + "QUICEncryptionLevelInitial", + "QUICEvent", + "QUICEventKind", + "QUICHandshakeDone", + "QUICNoEvent", + "QUICRejectedEarlyData", + "QUICServer", + "QUICSessionTicketOptions", + "QUICSetReadSecret", + "QUICSetWriteSecret", + "QUICTransportParameters", + "QUICTransportParametersRequired", + "QUICWriteData", "RecordHeaderError", "RenegotiateFreelyAsClient", "RenegotiateNever", @@ -493,6 +526,7 @@ var stdlib = map[string][]string{ "RequireAndVerifyClientCert", "RequireAnyClientCert", "Server", + "SessionState", "SignatureScheme", "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384", @@ -523,6 +557,7 @@ var stdlib = map[string][]string{ "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_RC4_128_SHA", "VerifyClientCertIfGiven", + "VersionName", "VersionSSL30", "VersionTLS10", "VersionTLS11", @@ -618,6 +653,7 @@ var stdlib = map[string][]string{ "PureEd25519", "RSA", "RevocationList", + "RevocationListEntry", "SHA1WithRSA", "SHA256WithRSA", "SHA256WithRSAPSS", @@ -1002,10 +1038,42 @@ var stdlib = map[string][]string{ "COMPRESS_LOOS", "COMPRESS_LOPROC", "COMPRESS_ZLIB", + "COMPRESS_ZSTD", "Chdr32", "Chdr64", "Class", "CompressionType", + "DF_1_CONFALT", + "DF_1_DIRECT", + "DF_1_DISPRELDNE", + "DF_1_DISPRELPND", + "DF_1_EDITED", + "DF_1_ENDFILTEE", + "DF_1_GLOBAL", + "DF_1_GLOBAUDIT", + "DF_1_GROUP", + "DF_1_IGNMULDEF", + "DF_1_INITFIRST", + "DF_1_INTERPOSE", + "DF_1_KMOD", + "DF_1_LOADFLTR", + "DF_1_NOCOMMON", + "DF_1_NODEFLIB", + "DF_1_NODELETE", + "DF_1_NODIRECT", + "DF_1_NODUMP", + "DF_1_NOHDR", + "DF_1_NOKSYMS", + "DF_1_NOOPEN", + "DF_1_NORELOC", + "DF_1_NOW", + "DF_1_ORIGIN", + "DF_1_PIE", + "DF_1_SINGLETON", + "DF_1_STUB", + "DF_1_SYMINTPOSE", + "DF_1_TRANS", + "DF_1_WEAKFILTER", "DF_BIND_NOW", "DF_ORIGIN", "DF_STATIC_TLS", @@ -1144,6 +1212,7 @@ var stdlib = map[string][]string{ "Dyn32", "Dyn64", "DynFlag", + "DynFlag1", "DynTag", "EI_ABIVERSION", "EI_CLASS", @@ -2111,6 +2180,7 @@ var stdlib = map[string][]string{ "R_PPC64_REL16_LO", "R_PPC64_REL24", "R_PPC64_REL24_NOTOC", + "R_PPC64_REL24_P9NOTOC", "R_PPC64_REL30", "R_PPC64_REL32", "R_PPC64_REL64", @@ -2848,6 +2918,7 @@ var stdlib = map[string][]string{ "MaxVarintLen16", "MaxVarintLen32", "MaxVarintLen64", + "NativeEndian", "PutUvarint", "PutVarint", "Read", @@ -2963,6 +3034,7 @@ var stdlib = map[string][]string{ }, "errors": { "As", + "ErrUnsupported", "Is", "Join", "New", @@ -2989,6 +3061,7 @@ var stdlib = map[string][]string{ "Arg", "Args", "Bool", + "BoolFunc", "BoolVar", "CommandLine", "ContinueOnError", @@ -3119,6 +3192,7 @@ var stdlib = map[string][]string{ "Inspect", "InterfaceType", "IsExported", + "IsGenerated", "KeyValueExpr", "LabeledStmt", "Lbl", @@ -3169,6 +3243,7 @@ var stdlib = map[string][]string{ "ArchChar", "Context", "Default", + "Directive", "FindOnly", "IgnoreVendor", "Import", @@ -3184,6 +3259,7 @@ var stdlib = map[string][]string{ "go/build/constraint": { "AndExpr", "Expr", + "GoVersion", "IsGoBuild", "IsPlusBuild", "NotExpr", @@ -3626,6 +3702,7 @@ var stdlib = map[string][]string{ "ErrBadHTML", "ErrBranchEnd", "ErrEndContext", + "ErrJSTemplate", "ErrNoSuchTemplate", "ErrOutputContext", "ErrPartialCharset", @@ -3870,6 +3947,8 @@ var stdlib = map[string][]string{ "FileInfo", "FileInfoToDirEntry", "FileMode", + "FormatDirEntry", + "FormatFileInfo", "Glob", "GlobFS", "ModeAppend", @@ -3942,6 +4021,78 @@ var stdlib = map[string][]string{ "SetPrefix", "Writer", }, + "log/slog": { + "Any", + "AnyValue", + "Attr", + "Bool", + "BoolValue", + "Debug", + "DebugContext", + "Default", + "Duration", + "DurationValue", + "Error", + "ErrorContext", + "Float64", + "Float64Value", + "Group", + "GroupValue", + "Handler", + "HandlerOptions", + "Info", + "InfoContext", + "Int", + "Int64", + "Int64Value", + "IntValue", + "JSONHandler", + "Kind", + "KindAny", + "KindBool", + "KindDuration", + "KindFloat64", + "KindGroup", + "KindInt64", + "KindLogValuer", + "KindString", + "KindTime", + "KindUint64", + "Level", + "LevelDebug", + "LevelError", + "LevelInfo", + "LevelKey", + "LevelVar", + "LevelWarn", + "Leveler", + "Log", + "LogAttrs", + "LogValuer", + "Logger", + "MessageKey", + "New", + "NewJSONHandler", + "NewLogLogger", + "NewRecord", + "NewTextHandler", + "Record", + "SetDefault", + "Source", + "SourceKey", + "String", + "StringValue", + "TextHandler", + "Time", + "TimeKey", + "TimeValue", + "Uint64", + "Uint64Value", + "Value", + "Warn", + "WarnContext", + "With", + }, "log/syslog": { "Dial", "LOG_ALERT", @@ -3977,6 +4128,13 @@ var stdlib = map[string][]string{ "Priority", "Writer", }, + "maps": { + "Clone", + "Copy", + "DeleteFunc", + "Equal", + "EqualFunc", + }, "math": { "Abs", "Acos", @@ -4371,6 +4529,7 @@ var stdlib = map[string][]string{ "ErrNoLocation", "ErrNotMultipart", "ErrNotSupported", + "ErrSchemeMismatch", "ErrServerClosed", "ErrShortBody", "ErrSkipAltProtocol", @@ -5084,6 +5243,8 @@ var stdlib = map[string][]string{ "NumCPU", "NumCgoCall", "NumGoroutine", + "PanicNilError", + "Pinner", "ReadMemStats", "ReadTrace", "SetBlockProfileRate", @@ -5172,6 +5333,37 @@ var stdlib = map[string][]string{ "Task", "WithRegion", }, + "slices": { + "BinarySearch", + "BinarySearchFunc", + "Clip", + "Clone", + "Compact", + "CompactFunc", + "Compare", + "CompareFunc", + "Contains", + "ContainsFunc", + "Delete", + "DeleteFunc", + "Equal", + "EqualFunc", + "Grow", + "Index", + "IndexFunc", + "Insert", + "IsSorted", + "IsSortedFunc", + "Max", + "MaxFunc", + "Min", + "MinFunc", + "Replace", + "Reverse", + "Sort", + "SortFunc", + "SortStableFunc", + }, "sort": { "Find", "Float64Slice", @@ -5242,6 +5434,7 @@ var stdlib = map[string][]string{ "Compare", "Contains", "ContainsAny", + "ContainsFunc", "ContainsRune", "Count", "Cut", @@ -5299,6 +5492,9 @@ var stdlib = map[string][]string{ "Mutex", "NewCond", "Once", + "OnceFunc", + "OnceValue", + "OnceValues", "Pool", "RWMutex", "WaitGroup", @@ -9135,10 +9331,12 @@ var stdlib = map[string][]string{ "SYS_AIO_CANCEL", "SYS_AIO_ERROR", "SYS_AIO_FSYNC", + "SYS_AIO_MLOCK", "SYS_AIO_READ", "SYS_AIO_RETURN", "SYS_AIO_SUSPEND", "SYS_AIO_SUSPEND_NOCANCEL", + "SYS_AIO_WAITCOMPLETE", "SYS_AIO_WRITE", "SYS_ALARM", "SYS_ARCH_PRCTL", @@ -9368,6 +9566,7 @@ var stdlib = map[string][]string{ "SYS_GET_MEMPOLICY", "SYS_GET_ROBUST_LIST", "SYS_GET_THREAD_AREA", + "SYS_GSSD_SYSCALL", "SYS_GTTY", "SYS_IDENTITYSVC", "SYS_IDLE", @@ -9411,8 +9610,24 @@ var stdlib = map[string][]string{ "SYS_KLDSYM", "SYS_KLDUNLOAD", "SYS_KLDUNLOADF", + "SYS_KMQ_NOTIFY", + "SYS_KMQ_OPEN", + "SYS_KMQ_SETATTR", + "SYS_KMQ_TIMEDRECEIVE", + "SYS_KMQ_TIMEDSEND", + "SYS_KMQ_UNLINK", "SYS_KQUEUE", "SYS_KQUEUE1", + "SYS_KSEM_CLOSE", + "SYS_KSEM_DESTROY", + "SYS_KSEM_GETVALUE", + "SYS_KSEM_INIT", + "SYS_KSEM_OPEN", + "SYS_KSEM_POST", + "SYS_KSEM_TIMEDWAIT", + "SYS_KSEM_TRYWAIT", + "SYS_KSEM_UNLINK", + "SYS_KSEM_WAIT", "SYS_KTIMER_CREATE", "SYS_KTIMER_DELETE", "SYS_KTIMER_GETOVERRUN", @@ -9504,11 +9719,14 @@ var stdlib = map[string][]string{ "SYS_NFSSVC", "SYS_NFSTAT", "SYS_NICE", + "SYS_NLM_SYSCALL", "SYS_NLSTAT", "SYS_NMOUNT", "SYS_NSTAT", "SYS_NTP_ADJTIME", "SYS_NTP_GETTIME", + "SYS_NUMA_GETAFFINITY", + "SYS_NUMA_SETAFFINITY", "SYS_OABI_SYSCALL_BASE", "SYS_OBREAK", "SYS_OLDFSTAT", @@ -9891,6 +10109,7 @@ var stdlib = map[string][]string{ "SYS___ACL_SET_FD", "SYS___ACL_SET_FILE", "SYS___ACL_SET_LINK", + "SYS___CAP_RIGHTS_GET", "SYS___CLONE", "SYS___DISABLE_THREADSIGNAL", "SYS___GETCWD", @@ -10574,6 +10793,7 @@ var stdlib = map[string][]string{ "Short", "T", "TB", + "Testing", "Verbose", }, "testing/fstest": { @@ -10603,6 +10823,9 @@ var stdlib = map[string][]string{ "SetupError", "Value", }, + "testing/slogtest": { + "TestHandler", + }, "text/scanner": { "Char", "Comment", @@ -10826,6 +11049,7 @@ var stdlib = map[string][]string{ "Cs", "Cuneiform", "Cypriot", + "Cypro_Minoan", "Cyrillic", "Dash", "Deprecated", @@ -10889,6 +11113,7 @@ var stdlib = map[string][]string{ "Kaithi", "Kannada", "Katakana", + "Kawi", "Kayah_Li", "Kharoshthi", "Khitan_Small_Script", @@ -10943,6 +11168,7 @@ var stdlib = map[string][]string{ "Myanmar", "N", "Nabataean", + "Nag_Mundari", "Nandinagari", "Nd", "New_Tai_Lue", @@ -10964,6 +11190,7 @@ var stdlib = map[string][]string{ "Old_Sogdian", "Old_South_Arabian", "Old_Turkic", + "Old_Uyghur", "Oriya", "Osage", "Osmanya", @@ -11038,6 +11265,7 @@ var stdlib = map[string][]string{ "Tai_Viet", "Takri", "Tamil", + "Tangsa", "Tangut", "Telugu", "Terminal_Punctuation", @@ -11052,6 +11280,7 @@ var stdlib = map[string][]string{ "ToLower", "ToTitle", "ToUpper", + "Toto", "TurkishCase", "Ugaritic", "Unified_Ideograph", @@ -11061,6 +11290,7 @@ var stdlib = map[string][]string{ "Vai", "Variation_Selector", "Version", + "Vithkuqi", "Wancho", "Warang_Citi", "White_Space", diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go index d9950b1f0..44719de17 100644 --- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go +++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go @@ -5,10 +5,6 @@ // Package packagesinternal exposes internal-only fields from go/packages. package packagesinternal -import ( - "golang.org/x/tools/internal/gocommand" -) - var GetForTest = func(p interface{}) string { return "" } var GetDepsErrors = func(p interface{}) []*PackageError { return nil } @@ -18,10 +14,6 @@ type PackageError struct { Err string // the error itself } -var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil } - -var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {} - var TypecheckCgo int var DepsErrors int // must be set as a LoadMode to call GetDepsErrors var ForTest int // must be set as a LoadMode to call GetForTest diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go index cfba8189f..cdab98853 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/common.go +++ b/vendor/golang.org/x/tools/internal/typeparams/common.go @@ -23,6 +23,7 @@ package typeparams import ( + "fmt" "go/ast" "go/token" "go/types" @@ -41,7 +42,7 @@ func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Ex switch e := n.(type) { case *ast.IndexExpr: return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack - case *IndexListExpr: + case *ast.IndexListExpr: return e.X, e.Lbrack, e.Indices, e.Rbrack } return nil, token.NoPos, nil, token.NoPos @@ -62,7 +63,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke Rbrack: rbrack, } default: - return &IndexListExpr{ + return &ast.IndexListExpr{ X: x, Lbrack: lbrack, Indices: indices, @@ -73,7 +74,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke // IsTypeParam reports whether t is a type parameter. func IsTypeParam(t types.Type) bool { - _, ok := t.(*TypeParam) + _, ok := t.(*types.TypeParam) return ok } @@ -99,12 +100,37 @@ func OriginMethod(fn *types.Func) *types.Func { // Receiver is a *types.Interface. return fn } - if ForNamed(named).Len() == 0 { + if named.TypeParams().Len() == 0 { // Receiver base has no type parameters, so we can avoid the lookup below. return fn } - orig := NamedTypeOrigin(named) + orig := named.Origin() gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name()) + + // This is a fix for a gopls crash (#60628) due to a go/types bug (#60634). In: + // package p + // type T *int + // func (*T) f() {} + // LookupFieldOrMethod(T, true, p, f)=nil, but NewMethodSet(*T)={(*T).f}. + // Here we make them consistent by force. + // (The go/types bug is general, but this workaround is reached only + // for generic T thanks to the early return above.) + if gfn == nil { + mset := types.NewMethodSet(types.NewPointer(orig)) + for i := 0; i < mset.Len(); i++ { + m := mset.At(i) + if m.Obj().Id() == fn.Id() { + gfn = m.Obj() + break + } + } + } + + // In golang/go#61196, we observe another crash, this time inexplicable. + if gfn == nil { + panic(fmt.Sprintf("missing origin method for %s.%s; named == origin: %t, named.NumMethods(): %d, origin.NumMethods(): %d", named, fn, named == orig, named.NumMethods(), orig.NumMethods())) + } + return gfn.(*types.Func) } @@ -131,7 +157,7 @@ func OriginMethod(fn *types.Func) *types.Func { // // In this case, GenericAssignableTo reports that instantiations of Container // are assignable to the corresponding instantiation of Interface. -func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { +func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool { // If V and T are not both named, or do not have matching non-empty type // parameter lists, fall back on types.AssignableTo. @@ -141,9 +167,9 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { return types.AssignableTo(V, T) } - vtparams := ForNamed(VN) - ttparams := ForNamed(TN) - if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || NamedTypeArgs(VN).Len() != 0 || NamedTypeArgs(TN).Len() != 0 { + vtparams := VN.TypeParams() + ttparams := TN.TypeParams() + if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 { return types.AssignableTo(V, T) } @@ -156,7 +182,7 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { // Minor optimization: ensure we share a context across the two // instantiations below. if ctxt == nil { - ctxt = NewContext() + ctxt = types.NewContext() } var targs []types.Type @@ -164,12 +190,12 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { targs = append(targs, vtparams.At(i)) } - vinst, err := Instantiate(ctxt, V, targs, true) + vinst, err := types.Instantiate(ctxt, V, targs, true) if err != nil { panic("type parameters should satisfy their own constraints") } - tinst, err := Instantiate(ctxt, T, targs, true) + tinst, err := types.Instantiate(ctxt, T, targs, true) if err != nil { return false } diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go index 993135ec9..7ea8840ea 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/coretype.go +++ b/vendor/golang.org/x/tools/internal/typeparams/coretype.go @@ -81,13 +81,13 @@ func CoreType(T types.Type) types.Type { // restrictions may be arbitrarily complex. For example, consider the // following: // -// type A interface{ ~string|~[]byte } +// type A interface{ ~string|~[]byte } // -// type B interface{ int|string } +// type B interface{ int|string } // -// type C interface { ~string|~int } +// type C interface { ~string|~int } // -// type T[P interface{ A|B; C }] int +// type T[P interface{ A|B; C }] int // // In this example, the structural type restriction of P is ~string|int: A|B // expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, @@ -108,15 +108,15 @@ func CoreType(T types.Type) types.Type { // // _NormalTerms makes no guarantees about the order of terms, except that it // is deterministic. -func _NormalTerms(typ types.Type) ([]*Term, error) { +func _NormalTerms(typ types.Type) ([]*types.Term, error) { switch typ := typ.(type) { - case *TypeParam: + case *types.TypeParam: return StructuralTerms(typ) - case *Union: + case *types.Union: return UnionTermSet(typ) case *types.Interface: return InterfaceTermSet(typ) default: - return []*Term{NewTerm(false, typ)}, nil + return []*types.Term{types.NewTerm(false, typ)}, nil } } diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go deleted file mode 100644 index 18212390e..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -// Enabled reports whether type parameters are enabled in the current build -// environment. -const Enabled = false diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go deleted file mode 100644 index d67148823..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typeparams - -// Note: this constant is in a separate file as this is the only acceptable -// diff between the <1.18 API of this package and the 1.18 API. - -// Enabled reports whether type parameters are enabled in the current build -// environment. -const Enabled = true diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go index 9c631b651..93c80fdc9 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go +++ b/vendor/golang.org/x/tools/internal/typeparams/normalize.go @@ -60,7 +60,7 @@ var ErrEmptyTypeSet = errors.New("empty type set") // // StructuralTerms makes no guarantees about the order of terms, except that it // is deterministic. -func StructuralTerms(tparam *TypeParam) ([]*Term, error) { +func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) { constraint := tparam.Constraint() if constraint == nil { return nil, fmt.Errorf("%s has nil constraint", tparam) @@ -78,7 +78,7 @@ func StructuralTerms(tparam *TypeParam) ([]*Term, error) { // // See the documentation of StructuralTerms for more information on // normalization. -func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { +func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) { return computeTermSet(iface) } @@ -88,11 +88,11 @@ func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { // // See the documentation of StructuralTerms for more information on // normalization. -func UnionTermSet(union *Union) ([]*Term, error) { +func UnionTermSet(union *types.Union) ([]*types.Term, error) { return computeTermSet(union) } -func computeTermSet(typ types.Type) ([]*Term, error) { +func computeTermSet(typ types.Type) ([]*types.Term, error) { tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) if err != nil { return nil, err @@ -103,9 +103,9 @@ func computeTermSet(typ types.Type) ([]*Term, error) { if tset.terms.isAll() { return nil, nil } - var terms []*Term + var terms []*types.Term for _, term := range tset.terms { - terms = append(terms, NewTerm(term.tilde, term.typ)) + terms = append(terms, types.NewTerm(term.tilde, term.typ)) } return terms, nil } @@ -162,7 +162,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in tset.terms = allTermlist for i := 0; i < u.NumEmbeddeds(); i++ { embedded := u.EmbeddedType(i) - if _, ok := embedded.Underlying().(*TypeParam); ok { + if _, ok := embedded.Underlying().(*types.TypeParam); ok { return nil, fmt.Errorf("invalid embedded type %T", embedded) } tset2, err := computeTermSetInternal(embedded, seen, depth+1) @@ -171,7 +171,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in } tset.terms = tset.terms.intersect(tset2.terms) } - case *Union: + case *types.Union: // The term set of a union is the union of term sets of its terms. tset.terms = nil for i := 0; i < u.Len(); i++ { @@ -184,7 +184,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in return nil, err } terms = tset2.terms - case *TypeParam, *Union: + case *types.TypeParam, *types.Union: // A stand-alone type parameter or union is not permitted as union // term. return nil, fmt.Errorf("invalid union term %T", t) @@ -199,7 +199,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) } } - case *TypeParam: + case *types.TypeParam: panic("unreachable") default: // For all other types, the term set is just a single non-tilde term diff --git a/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/vendor/golang.org/x/tools/internal/typeparams/termlist.go index 933106a23..cbd12f801 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/termlist.go +++ b/vendor/golang.org/x/tools/internal/typeparams/termlist.go @@ -30,7 +30,7 @@ func (xl termlist) String() string { var buf bytes.Buffer for i, x := range xl { if i > 0 { - buf.WriteString(" ∪ ") + buf.WriteString(" | ") } buf.WriteString(x.String()) } diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go deleted file mode 100644 index b4788978f..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -import ( - "go/ast" - "go/token" - "go/types" -) - -func unsupported() { - panic("type parameters are unsupported at this go version") -} - -// IndexListExpr is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type IndexListExpr struct { - ast.Expr - X ast.Expr // expression - Lbrack token.Pos // position of "[" - Indices []ast.Expr // index expressions - Rbrack token.Pos // position of "]" -} - -// ForTypeSpec returns an empty field list, as type parameters on not supported -// at this Go version. -func ForTypeSpec(*ast.TypeSpec) *ast.FieldList { - return nil -} - -// ForFuncType returns an empty field list, as type parameters are not -// supported at this Go version. -func ForFuncType(*ast.FuncType) *ast.FieldList { - return nil -} - -// TypeParam is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type TypeParam struct{ types.Type } - -func (*TypeParam) Index() int { unsupported(); return 0 } -func (*TypeParam) Constraint() types.Type { unsupported(); return nil } -func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil } - -// TypeParamList is a placeholder for an empty type parameter list. -type TypeParamList struct{} - -func (*TypeParamList) Len() int { return 0 } -func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil } - -// TypeList is a placeholder for an empty type list. -type TypeList struct{} - -func (*TypeList) Len() int { return 0 } -func (*TypeList) At(int) types.Type { unsupported(); return nil } - -// NewTypeParam is unsupported at this Go version, and panics. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - unsupported() - return nil -} - -// SetTypeParamConstraint is unsupported at this Go version, and panics. -func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { - unsupported() -} - -// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or -// typeParams is non-empty. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - if len(recvTypeParams) != 0 || len(typeParams) != 0 { - panic("signatures cannot have type parameters at this Go version") - } - return types.NewSignature(recv, params, results, variadic) -} - -// ForSignature returns an empty slice. -func ForSignature(*types.Signature) *TypeParamList { - return nil -} - -// RecvTypeParams returns a nil slice. -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return nil -} - -// IsComparable returns false, as no interfaces are type-restricted at this Go -// version. -func IsComparable(*types.Interface) bool { - return false -} - -// IsMethodSet returns true, as no interfaces are type-restricted at this Go -// version. -func IsMethodSet(*types.Interface) bool { - return true -} - -// IsImplicit returns false, as no interfaces are implicit at this Go version. -func IsImplicit(*types.Interface) bool { - return false -} - -// MarkImplicit does nothing, because this Go version does not have implicit -// interfaces. -func MarkImplicit(*types.Interface) {} - -// ForNamed returns an empty type parameter list, as type parameters are not -// supported at this Go version. -func ForNamed(*types.Named) *TypeParamList { - return nil -} - -// SetForNamed panics if tparams is non-empty. -func SetForNamed(_ *types.Named, tparams []*TypeParam) { - if len(tparams) > 0 { - unsupported() - } -} - -// NamedTypeArgs returns nil. -func NamedTypeArgs(*types.Named) *TypeList { - return nil -} - -// NamedTypeOrigin is the identity method at this Go version. -func NamedTypeOrigin(named *types.Named) types.Type { - return named -} - -// Term holds information about a structural type restriction. -type Term struct { - tilde bool - typ types.Type -} - -func (m *Term) Tilde() bool { return m.tilde } -func (m *Term) Type() types.Type { return m.typ } -func (m *Term) String() string { - pre := "" - if m.tilde { - pre = "~" - } - return pre + m.typ.String() -} - -// NewTerm is unsupported at this Go version, and panics. -func NewTerm(tilde bool, typ types.Type) *Term { - return &Term{tilde, typ} -} - -// Union is a placeholder type, as type parameters are not supported at this Go -// version. Its methods panic on use. -type Union struct{ types.Type } - -func (*Union) Len() int { return 0 } -func (*Union) Term(i int) *Term { unsupported(); return nil } - -// NewUnion is unsupported at this Go version, and panics. -func NewUnion(terms []*Term) *Union { - unsupported() - return nil -} - -// InitInstanceInfo is a noop at this Go version. -func InitInstanceInfo(*types.Info) {} - -// Instance is a placeholder type, as type parameters are not supported at this -// Go version. -type Instance struct { - TypeArgs *TypeList - Type types.Type -} - -// GetInstances returns a nil map, as type parameters are not supported at this -// Go version. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil } - -// Context is a placeholder type, as type parameters are not supported at -// this Go version. -type Context struct{} - -// NewContext returns a placeholder Context instance. -func NewContext() *Context { - return &Context{} -} - -// Instantiate is unsupported on this Go version, and panics. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - unsupported() - return nil, nil -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go deleted file mode 100644 index 114a36b86..000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typeparams - -import ( - "go/ast" - "go/types" -) - -// IndexListExpr is an alias for ast.IndexListExpr. -type IndexListExpr = ast.IndexListExpr - -// ForTypeSpec returns n.TypeParams. -func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList { - if n == nil { - return nil - } - return n.TypeParams -} - -// ForFuncType returns n.TypeParams. -func ForFuncType(n *ast.FuncType) *ast.FieldList { - if n == nil { - return nil - } - return n.TypeParams -} - -// TypeParam is an alias for types.TypeParam -type TypeParam = types.TypeParam - -// TypeParamList is an alias for types.TypeParamList -type TypeParamList = types.TypeParamList - -// TypeList is an alias for types.TypeList -type TypeList = types.TypeList - -// NewTypeParam calls types.NewTypeParam. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - return types.NewTypeParam(name, constraint) -} - -// SetTypeParamConstraint calls tparam.SetConstraint(constraint). -func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { - tparam.SetConstraint(constraint) -} - -// NewSignatureType calls types.NewSignatureType. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic) -} - -// ForSignature returns sig.TypeParams() -func ForSignature(sig *types.Signature) *TypeParamList { - return sig.TypeParams() -} - -// RecvTypeParams returns sig.RecvTypeParams(). -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return sig.RecvTypeParams() -} - -// IsComparable calls iface.IsComparable(). -func IsComparable(iface *types.Interface) bool { - return iface.IsComparable() -} - -// IsMethodSet calls iface.IsMethodSet(). -func IsMethodSet(iface *types.Interface) bool { - return iface.IsMethodSet() -} - -// IsImplicit calls iface.IsImplicit(). -func IsImplicit(iface *types.Interface) bool { - return iface.IsImplicit() -} - -// MarkImplicit calls iface.MarkImplicit(). -func MarkImplicit(iface *types.Interface) { - iface.MarkImplicit() -} - -// ForNamed extracts the (possibly empty) type parameter object list from -// named. -func ForNamed(named *types.Named) *TypeParamList { - return named.TypeParams() -} - -// SetForNamed sets the type params tparams on n. Each tparam must be of -// dynamic type *types.TypeParam. -func SetForNamed(n *types.Named, tparams []*TypeParam) { - n.SetTypeParams(tparams) -} - -// NamedTypeArgs returns named.TypeArgs(). -func NamedTypeArgs(named *types.Named) *TypeList { - return named.TypeArgs() -} - -// NamedTypeOrigin returns named.Orig(). -func NamedTypeOrigin(named *types.Named) types.Type { - return named.Origin() -} - -// Term is an alias for types.Term. -type Term = types.Term - -// NewTerm calls types.NewTerm. -func NewTerm(tilde bool, typ types.Type) *Term { - return types.NewTerm(tilde, typ) -} - -// Union is an alias for types.Union -type Union = types.Union - -// NewUnion calls types.NewUnion. -func NewUnion(terms []*Term) *Union { - return types.NewUnion(terms) -} - -// InitInstanceInfo initializes info to record information about type and -// function instances. -func InitInstanceInfo(info *types.Info) { - info.Instances = make(map[*ast.Ident]types.Instance) -} - -// Instance is an alias for types.Instance. -type Instance = types.Instance - -// GetInstances returns info.Instances. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { - return info.Instances -} - -// Context is an alias for types.Context. -type Context = types.Context - -// NewContext calls types.NewContext. -func NewContext() *Context { - return types.NewContext() -} - -// Instantiate calls types.Instantiate. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - return types.Instantiate(ctxt, typ, targs, validate) -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go index 7ddee28d9..7350bb702 100644 --- a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go +++ b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go @@ -10,11 +10,10 @@ import "go/types" // A term describes elementary type sets: // -// ∅: (*term)(nil) == ∅ // set of no types (empty set) -// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) -// T: &term{false, T} == {T} // set of type T -// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t -// +// ∅: (*term)(nil) == ∅ // set of no types (empty set) +// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) +// T: &term{false, T} == {T} // set of type T +// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t type term struct { tilde bool // valid if typ != nil typ types.Type diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go index 3c53fbc63..ce7d4351b 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/types.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -11,8 +11,6 @@ import ( "go/types" "reflect" "unsafe" - - "golang.org/x/tools/go/types/objectpath" ) func SetUsesCgo(conf *types.Config) bool { @@ -52,10 +50,3 @@ func ReadGo116ErrorData(err types.Error) (code ErrorCode, start, end token.Pos, } var SetGoVersion = func(conf *types.Config, version string) bool { return false } - -// NewObjectpathEncoder returns a function closure equivalent to -// objectpath.For but amortized for multiple (sequential) calls. -// It is a temporary workaround, pending the approval of proposal 58668. -// -//go:linkname NewObjectpathFunc golang.org/x/tools/go/types/objectpath.newEncoderFor -func NewObjectpathFunc() func(types.Object) (objectpath.Path, error) diff --git a/vendor/golang.org/x/tools/internal/versions/gover.go b/vendor/golang.org/x/tools/internal/versions/gover.go new file mode 100644 index 000000000..bbabcd22e --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/gover.go @@ -0,0 +1,172 @@ +// Copyright 2023 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. + +// This is a fork of internal/gover for use by x/tools until +// go1.21 and earlier are no longer supported by x/tools. + +package versions + +import "strings" + +// A gover is a parsed Go gover: major[.Minor[.Patch]][kind[pre]] +// The numbers are the original decimal strings to avoid integer overflows +// and since there is very little actual math. (Probably overflow doesn't matter in practice, +// but at the time this code was written, there was an existing test that used +// go1.99999999999, which does not fit in an int on 32-bit platforms. +// The "big decimal" representation avoids the problem entirely.) +type gover struct { + major string // decimal + minor string // decimal or "" + patch string // decimal or "" + kind string // "", "alpha", "beta", "rc" + pre string // decimal or "" +} + +// compare returns -1, 0, or +1 depending on whether +// x < y, x == y, or x > y, interpreted as toolchain versions. +// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21". +// Malformed versions compare less than well-formed versions and equal to each other. +// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0". +func compare(x, y string) int { + vx := parse(x) + vy := parse(y) + + if c := cmpInt(vx.major, vy.major); c != 0 { + return c + } + if c := cmpInt(vx.minor, vy.minor); c != 0 { + return c + } + if c := cmpInt(vx.patch, vy.patch); c != 0 { + return c + } + if c := strings.Compare(vx.kind, vy.kind); c != 0 { // "" < alpha < beta < rc + return c + } + if c := cmpInt(vx.pre, vy.pre); c != 0 { + return c + } + return 0 +} + +// lang returns the Go language version. For example, lang("1.2.3") == "1.2". +func lang(x string) string { + v := parse(x) + if v.minor == "" || v.major == "1" && v.minor == "0" { + return v.major + } + return v.major + "." + v.minor +} + +// isValid reports whether the version x is valid. +func isValid(x string) bool { + return parse(x) != gover{} +} + +// parse parses the Go version string x into a version. +// It returns the zero version if x is malformed. +func parse(x string) gover { + var v gover + + // Parse major version. + var ok bool + v.major, x, ok = cutInt(x) + if !ok { + return gover{} + } + if x == "" { + // Interpret "1" as "1.0.0". + v.minor = "0" + v.patch = "0" + return v + } + + // Parse . before minor version. + if x[0] != '.' { + return gover{} + } + + // Parse minor version. + v.minor, x, ok = cutInt(x[1:]) + if !ok { + return gover{} + } + if x == "" { + // Patch missing is same as "0" for older versions. + // Starting in Go 1.21, patch missing is different from explicit .0. + if cmpInt(v.minor, "21") < 0 { + v.patch = "0" + } + return v + } + + // Parse patch if present. + if x[0] == '.' { + v.patch, x, ok = cutInt(x[1:]) + if !ok || x != "" { + // Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != ""). + // Allowing them would be a bit confusing because we already have: + // 1.21 < 1.21rc1 + // But a prerelease of a patch would have the opposite effect: + // 1.21.3rc1 < 1.21.3 + // We've never needed them before, so let's not start now. + return gover{} + } + return v + } + + // Parse prerelease. + i := 0 + for i < len(x) && (x[i] < '0' || '9' < x[i]) { + if x[i] < 'a' || 'z' < x[i] { + return gover{} + } + i++ + } + if i == 0 { + return gover{} + } + v.kind, x = x[:i], x[i:] + if x == "" { + return v + } + v.pre, x, ok = cutInt(x) + if !ok || x != "" { + return gover{} + } + + return v +} + +// cutInt scans the leading decimal number at the start of x to an integer +// and returns that value and the rest of the string. +func cutInt(x string) (n, rest string, ok bool) { + i := 0 + for i < len(x) && '0' <= x[i] && x[i] <= '9' { + i++ + } + if i == 0 || x[0] == '0' && i != 1 { // no digits or unnecessary leading zero + return "", "", false + } + return x[:i], x[i:], true +} + +// cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers. +// (Copied from golang.org/x/mod/semver's compareInt.) +func cmpInt(x, y string) int { + if x == y { + return 0 + } + if len(x) < len(y) { + return -1 + } + if len(x) > len(y) { + return +1 + } + if x < y { + return -1 + } else { + return +1 + } +} diff --git a/vendor/golang.org/x/tools/internal/versions/types.go b/vendor/golang.org/x/tools/internal/versions/types.go new file mode 100644 index 000000000..562eef21f --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/types.go @@ -0,0 +1,19 @@ +// Copyright 2023 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 versions + +import ( + "go/types" +) + +// GoVersion returns the Go version of the type package. +// It returns zero if no version can be determined. +func GoVersion(pkg *types.Package) string { + // TODO(taking): x/tools can call GoVersion() [from 1.21] after 1.25. + if pkg, ok := any(pkg).(interface{ GoVersion() string }); ok { + return pkg.GoVersion() + } + return "" +} diff --git a/vendor/golang.org/x/tools/internal/versions/types_go121.go b/vendor/golang.org/x/tools/internal/versions/types_go121.go new file mode 100644 index 000000000..a7b79207a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/types_go121.go @@ -0,0 +1,20 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.22 +// +build !go1.22 + +package versions + +import ( + "go/ast" + "go/types" +) + +// FileVersions always reports the a file's Go version as the +// zero version at this Go version. +func FileVersions(info *types.Info, file *ast.File) string { return "" } + +// InitFileVersions is a noop at this Go version. +func InitFileVersions(*types.Info) {} diff --git a/vendor/golang.org/x/tools/internal/versions/types_go122.go b/vendor/golang.org/x/tools/internal/versions/types_go122.go new file mode 100644 index 000000000..7b9ba89a8 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/types_go122.go @@ -0,0 +1,24 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.22 +// +build go1.22 + +package versions + +import ( + "go/ast" + "go/types" +) + +// FileVersions maps a file to the file's semantic Go version. +// The reported version is the zero version if a version cannot be determined. +func FileVersions(info *types.Info, file *ast.File) string { + return info.FileVersions[file] +} + +// InitFileVersions initializes info to record Go versions for Go files. +func InitFileVersions(info *types.Info) { + info.FileVersions = make(map[*ast.File]string) +} diff --git a/vendor/golang.org/x/tools/internal/versions/versions.go b/vendor/golang.org/x/tools/internal/versions/versions.go new file mode 100644 index 000000000..e16f6c33a --- /dev/null +++ b/vendor/golang.org/x/tools/internal/versions/versions.go @@ -0,0 +1,52 @@ +// Copyright 2023 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 versions + +// Note: If we use build tags to use go/versions when go >=1.22, +// we run into go.dev/issue/53737. Under some operations users would see an +// import of "go/versions" even if they would not compile the file. +// For example, during `go get -u ./...` (go.dev/issue/64490) we do not try to include +// For this reason, this library just a clone of go/versions for the moment. + +// Lang returns the Go language version for version x. +// If x is not a valid version, Lang returns the empty string. +// For example: +// +// Lang("go1.21rc2") = "go1.21" +// Lang("go1.21.2") = "go1.21" +// Lang("go1.21") = "go1.21" +// Lang("go1") = "go1" +// Lang("bad") = "" +// Lang("1.21") = "" +func Lang(x string) string { + v := lang(stripGo(x)) + if v == "" { + return "" + } + return x[:2+len(v)] // "go"+v without allocation +} + +// Compare returns -1, 0, or +1 depending on whether +// x < y, x == y, or x > y, interpreted as Go versions. +// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21". +// Invalid versions, including the empty string, compare less than +// valid versions and equal to each other. +// The language version "go1.21" compares less than the +// release candidate and eventual releases "go1.21rc1" and "go1.21.0". +// Custom toolchain suffixes are ignored during comparison: +// "go1.21.0" and "go1.21.0-bigcorp" are equal. +func Compare(x, y string) int { return compare(stripGo(x), stripGo(y)) } + +// IsValid reports whether the version x is valid. +func IsValid(x string) bool { return isValid(stripGo(x)) } + +// stripGo converts from a "go1.21" version to a "1.21" version. +// If v does not start with "go", stripGo returns the empty string (a known invalid version). +func stripGo(v string) string { + if len(v) < 2 || v[:2] != "go" { + return "" + } + return v[2:] +} diff --git a/vendor/golang.org/x/vuln/client/cache.go b/vendor/golang.org/x/vuln/client/cache.go deleted file mode 100644 index d60a1d2d2..000000000 --- a/vendor/golang.org/x/vuln/client/cache.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2021 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 client - -import ( - "time" - - "golang.org/x/vuln/osv" -) - -// A Cache caches vuln DB entries for modules. -// A single cache can support multiple DBs from different sources, each with a -// different name. -type Cache interface { - // ReadIndex returns the index for the given DB along with the time it was - // last read from the source. - ReadIndex(dbName string) (DBIndex, time.Time, error) - - // WriteIndex stores in the index and associated time for the given DB. - WriteIndex(dbName string, index DBIndex, t time.Time) error - - // ReadEntries returns the entries for modulePath in the named DB. - ReadEntries(dbName, modulePath string) ([]*osv.Entry, error) - - // WriteEntries stores the entries associated with modulePath in the named - // DB. - WriteEntries(dbName, modulePath string, entries []*osv.Entry) error -} diff --git a/vendor/golang.org/x/vuln/client/client.go b/vendor/golang.org/x/vuln/client/client.go deleted file mode 100644 index d633a2a7e..000000000 --- a/vendor/golang.org/x/vuln/client/client.go +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2021 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 client provides an interface for accessing vulnerability -// databases, via either HTTP or local filesystem access. -// -// The protocol is described at https://go.dev/security/vulndb/#protocol. -// -// The expected database layout is the same for both HTTP and local -// databases. The database index is located at the root of the -// database, and contains a list of all of the vulnerable modules -// documented in the database and the time the most recent vulnerability -// was added. The index file is called index.json, and has the -// following format: -// -// map[string]time.Time (DBIndex) -// -// Each vulnerable module is represented by an individual JSON file -// which contains all of the vulnerabilities in that module. The path -// for each module file is simply the import path of the module. -// For example, vulnerabilities in golang.org/x/crypto are contained in the -// golang.org/x/crypto.json file. The per-module JSON files contain a slice of -// https://pkg.go.dev/golang.org/x/vuln/osv#Entry. -// -// A single client.Client can be used to access multiple vulnerability -// databases. When looking up vulnerable modules, each database is -// consulted, and results are merged together. -package client - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path" - "path/filepath" - "sort" - "strings" - "time" - - "golang.org/x/mod/module" - "golang.org/x/vuln/internal" - "golang.org/x/vuln/internal/derrors" - "golang.org/x/vuln/osv" -) - -// DBIndex contains a mapping of vulnerable packages to the last time a new -// vulnerability was added to the database. -type DBIndex map[string]time.Time - -// Client interface for fetching vulnerabilities based on module path or ID. -type Client interface { - // GetByModule returns the entries that affect the given module path. - // It returns (nil, nil) if there are none. - GetByModule(context.Context, string) ([]*osv.Entry, error) - - // GetByID returns the entry with the given ID, or (nil, nil) if there isn't - // one. - GetByID(context.Context, string) (*osv.Entry, error) - - // GetByAlias returns the entries that have the given aliases, or (nil, nil) - // if there are none. - GetByAlias(context.Context, string) ([]*osv.Entry, error) - - // ListIDs returns the IDs of all entries in the database. - ListIDs(context.Context) ([]string, error) - - // LastModifiedTime returns the time that the database was last modified. - // It can be used by tools that periodically check for vulnerabilities - // to avoid repeating work. - LastModifiedTime(context.Context) (time.Time, error) - - unexported() // ensures that adding a method won't break users -} - -type source interface { - Client - Index(context.Context) (DBIndex, error) -} - -type localSource struct { - dir string -} - -func (*localSource) unexported() {} - -func (ls *localSource) GetByModule(_ context.Context, modulePath string) (_ []*osv.Entry, err error) { - defer derrors.Wrap(&err, "localSource.GetByModule(%q)", modulePath) - epath, err := EscapeModulePath(modulePath) - if err != nil { - return nil, err - } - content, err := os.ReadFile(filepath.Join(ls.dir, epath+".json")) - if os.IsNotExist(err) { - return nil, nil - } else if err != nil { - return nil, err - } - var e []*osv.Entry - if err = json.Unmarshal(content, &e); err != nil { - return nil, err - } - return e, nil -} - -func (ls *localSource) GetByID(_ context.Context, id string) (_ *osv.Entry, err error) { - defer derrors.Wrap(&err, "GetByID(%q)", id) - content, err := os.ReadFile(filepath.Join(ls.dir, internal.IDDirectory, id+".json")) - if os.IsNotExist(err) { - return nil, nil - } else if err != nil { - return nil, err - } - var e osv.Entry - if err = json.Unmarshal(content, &e); err != nil { - return nil, err - } - return &e, nil -} - -func (ls *localSource) GetByAlias(ctx context.Context, alias string) (entries []*osv.Entry, err error) { - defer derrors.Wrap(&err, "localSource.GetByAlias(%q)", alias) - - aliasToIDs, err := localReadJSON[map[string][]string](ctx, ls, "aliases.json") - if err != nil { - return nil, err - } - ids := aliasToIDs[alias] - if len(ids) == 0 { - return nil, nil - } - return getByIDs(ctx, ls, ids) -} - -func getByIDs(ctx context.Context, s source, ids []string) ([]*osv.Entry, error) { - var entries []*osv.Entry - for _, id := range ids { - e, err := s.GetByID(ctx, id) - if err != nil { - return nil, err - } - entries = append(entries, e) - } - return entries, nil -} - -func (ls *localSource) ListIDs(ctx context.Context) (_ []string, err error) { - defer derrors.Wrap(&err, "ListIDs()") - - return localReadJSON[[]string](ctx, ls, filepath.Join(internal.IDDirectory, "index.json")) -} - -func (ls *localSource) LastModifiedTime(context.Context) (_ time.Time, err error) { - defer derrors.Wrap(&err, "LastModifiedTime()") - - // Assume that if anything changes, the index does. - info, err := os.Stat(filepath.Join(ls.dir, "index.json")) - if err != nil { - return time.Time{}, err - } - return info.ModTime(), nil -} - -func (ls *localSource) Index(ctx context.Context) (_ DBIndex, err error) { - defer derrors.Wrap(&err, "Index()") - - return localReadJSON[DBIndex](ctx, ls, "index.json") -} - -func localReadJSON[T any](_ context.Context, ls *localSource, relativePath string) (T, error) { - var zero T - content, err := os.ReadFile(filepath.Join(ls.dir, relativePath)) - if err != nil { - return zero, err - } - var t T - if err := json.Unmarshal(content, &t); err != nil { - return zero, err - } - return t, nil -} - -type httpSource struct { - url string // the base URI of the source (without trailing "/"). e.g. https://vuln.golang.org - c *http.Client - cache Cache - dbName string -} - -func (hs *httpSource) Index(ctx context.Context) (_ DBIndex, err error) { - defer derrors.Wrap(&err, "Index()") - - var cachedIndex DBIndex - var cachedIndexRetrieved *time.Time - - if hs.cache != nil { - index, retrieved, err := hs.cache.ReadIndex(hs.dbName) - if err != nil { - return nil, err - } - - cachedIndex = index - if cachedIndex != nil { - if time.Since(retrieved) < time.Hour*2 { - return cachedIndex, nil - } - - cachedIndexRetrieved = &retrieved - } - } - - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/index.json", hs.url), nil) - if err != nil { - return nil, err - } - if cachedIndexRetrieved != nil { - req.Header.Add("If-Modified-Since", cachedIndexRetrieved.Format(http.TimeFormat)) - } - resp, err := hs.c.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if cachedIndexRetrieved != nil && resp.StatusCode == http.StatusNotModified { - // If status has not been modified, this is equivalent to returning the - // same index. We update the timestamp so the next cache index read does - // not require a roundtrip to the server. - if err = hs.cache.WriteIndex(hs.dbName, cachedIndex, time.Now()); err != nil { - return nil, err - } - return cachedIndex, nil - } - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) - } - b, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - var index DBIndex - if err = json.Unmarshal(b, &index); err != nil { - return nil, err - } - - if hs.cache != nil { - if err = hs.cache.WriteIndex(hs.dbName, index, time.Now()); err != nil { - return nil, err - } - } - - return index, nil -} - -func (*httpSource) unexported() {} - -func (hs *httpSource) GetByModule(ctx context.Context, modulePath string) (_ []*osv.Entry, err error) { - defer derrors.Wrap(&err, "httpSource.GetByModule(%q)", modulePath) - - index, err := hs.Index(ctx) - if err != nil { - return nil, err - } - - lastModified, present := index[modulePath] - if !present { - return nil, nil - } - - if hs.cache != nil { - cached, err := hs.cache.ReadEntries(hs.dbName, modulePath) - if err != nil { - return nil, err - } - if len(cached) > 0 && !latestModifiedTime(cached).Before(lastModified) { - return cached, nil - } - } - - epath, err := EscapeModulePath(modulePath) - if err != nil { - return nil, err - } - entries, err := httpReadJSON[[]*osv.Entry](ctx, hs, epath+".json") - if err != nil || entries == nil { - return nil, err - } - // TODO: we may want to check that the returned entries actually match - // the module we asked about, so that the cache cannot be poisoned - if hs.cache != nil { - if err := hs.cache.WriteEntries(hs.dbName, modulePath, entries); err != nil { - return nil, err - } - } - return entries, nil -} - -// Pseudo-module paths used for parts of the Go system. -// These are technically not valid module paths, so we -// mustn't pass them to module.EscapePath. -// Keep in sync with vulndb/internal/database/generate.go. -var specialCaseModulePaths = map[string]bool{ - "stdlib": true, - "toolchain": true, -} - -// EscapeModulePath should be called by cache implementations or other users of -// this package that want to use module paths as filesystem paths. It is like -// golang.org/x/mod/module, but accounts for special paths used by the -// vulnerability database. -func EscapeModulePath(path string) (string, error) { - if specialCaseModulePaths[path] { - return path, nil - } - return module.EscapePath(path) -} - -func latestModifiedTime(entries []*osv.Entry) time.Time { - var t time.Time - for _, e := range entries { - if e.Modified.After(t) { - t = e.Modified - } - } - return t -} - -func (hs *httpSource) GetByID(ctx context.Context, id string) (_ *osv.Entry, err error) { - defer derrors.Wrap(&err, "GetByID(%q)", id) - - return httpReadJSON[*osv.Entry](ctx, hs, fmt.Sprintf("%s/%s.json", internal.IDDirectory, id)) -} - -func (hs *httpSource) GetByAlias(ctx context.Context, alias string) (entries []*osv.Entry, err error) { - defer derrors.Wrap(&err, "httpSource.GetByAlias(%q)", alias) - - aliasToIDs, err := httpReadJSON[map[string][]string](ctx, hs, "aliases.json") - if err != nil { - return nil, err - } - ids := aliasToIDs[alias] - if len(ids) == 0 { - return nil, nil - } - return getByIDs(ctx, hs, ids) -} - -func (hs *httpSource) ListIDs(ctx context.Context) (_ []string, err error) { - defer derrors.Wrap(&err, "ListIDs()") - - return httpReadJSON[[]string](ctx, hs, path.Join(internal.IDDirectory, "index.json")) -} - -func httpReadJSON[T any](ctx context.Context, hs *httpSource, relativePath string) (T, error) { - var zero T - content, err := hs.readBody(ctx, fmt.Sprintf("%s/%s", hs.url, relativePath)) - if err != nil { - return zero, err - } - if len(content) == 0 { - return zero, nil - } - var t T - if err := json.Unmarshal(content, &t); err != nil { - return zero, err - } - return t, nil -} - -// This is the format for the last-modified header, as described at -// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified. -var lastModifiedFormat = "Mon, 2 Jan 2006 15:04:05 GMT" - -func (hs *httpSource) LastModifiedTime(ctx context.Context) (_ time.Time, err error) { - defer derrors.Wrap(&err, "LastModifiedTime()") - - // Assume that if anything changes, the index does. - url := fmt.Sprintf("%s/index.json", hs.url) - req, err := http.NewRequestWithContext(ctx, http.MethodHead, url, nil) - if err != nil { - return time.Time{}, err - } - resp, err := hs.c.Do(req) - if err != nil { - return time.Time{}, err - } - if resp.StatusCode != 200 { - return time.Time{}, fmt.Errorf("got status code %d", resp.StatusCode) - } - h := resp.Header.Get("Last-Modified") - return time.Parse(lastModifiedFormat, h) -} - -func (hs *httpSource) readBody(ctx context.Context, url string) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) - if err != nil { - return nil, err - } - resp, err := hs.c.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode == http.StatusNotFound { - return nil, nil - } - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("got HTTP status %s", resp.Status) - } - // might want this to be a LimitedReader - return io.ReadAll(resp.Body) -} - -type client struct { - sources []source -} - -type Options struct { - HTTPClient *http.Client - HTTPCache Cache -} - -func NewClient(sources []string, opts Options) (_ Client, err error) { - defer derrors.Wrap(&err, "NewClient(%v, opts)", sources) - c := &client{} - for _, uri := range sources { - uri = strings.TrimRight(uri, "/") - // should parse the URI out here instead of in there - switch { - case strings.HasPrefix(uri, "http://") || strings.HasPrefix(uri, "https://"): - hs := &httpSource{url: uri} - url, err := url.Parse(uri) - if err != nil { - return nil, err - } - hs.dbName = url.Hostname() - if opts.HTTPCache != nil { - hs.cache = opts.HTTPCache - } - if opts.HTTPClient != nil { - hs.c = opts.HTTPClient - } else { - hs.c = new(http.Client) - } - c.sources = append(c.sources, hs) - case strings.HasPrefix(uri, "file://"): - dir := strings.TrimPrefix(uri, "file://") - fi, err := os.Stat(dir) - if err != nil { - return nil, err - } - if !fi.IsDir() { - return nil, fmt.Errorf("%s is not a directory", dir) - } - c.sources = append(c.sources, &localSource{dir: dir}) - default: - return nil, fmt.Errorf("source %q has unsupported scheme", uri) - } - } - return c, nil -} - -func (*client) unexported() {} - -func (c *client) GetByModule(ctx context.Context, module string) (_ []*osv.Entry, err error) { - defer derrors.Wrap(&err, "GetByModule(%q)", module) - return c.unionEntries(ctx, func(c Client) ([]*osv.Entry, error) { - return c.GetByModule(ctx, module) - }) -} - -func (c *client) GetByAlias(ctx context.Context, alias string) (entries []*osv.Entry, err error) { - defer derrors.Wrap(&err, "GetByAlias(%q)", alias) - return c.unionEntries(ctx, func(c Client) ([]*osv.Entry, error) { - return c.GetByAlias(ctx, alias) - }) -} - -// unionEntries returns the union of all entries obtained by calling get on the client's sources. -func (c *client) unionEntries(ctx context.Context, get func(Client) ([]*osv.Entry, error)) ([]*osv.Entry, error) { - var entries []*osv.Entry - // probably should be parallelized - seen := map[string]bool{} - for _, s := range c.sources { - es, err := get(s) - if err != nil { - return nil, err // be failure tolerant? - } - for _, e := range es { - if !seen[e.ID] { - entries = append(entries, e) - seen[e.ID] = true - } - } - } - return entries, nil -} - -func (c *client) GetByID(ctx context.Context, id string) (_ *osv.Entry, err error) { - defer derrors.Wrap(&err, "GetByID(%q)", id) - for _, s := range c.sources { - entry, err := s.GetByID(ctx, id) - if err != nil { - return nil, err // be failure tolerant? - } - if entry != nil { - return entry, nil - } - } - return nil, nil -} - -// ListIDs returns the union of the IDs from all sources, -// sorted lexically. -func (c *client) ListIDs(ctx context.Context) (_ []string, err error) { - defer derrors.Wrap(&err, "ListIDs()") - idSet := map[string]bool{} - for _, s := range c.sources { - ids, err := s.ListIDs(ctx) - if err != nil { - return nil, err - } - for _, id := range ids { - idSet[id] = true - } - } - var ids []string - for id := range idSet { - ids = append(ids, id) - } - sort.Strings(ids) - return ids, nil -} - -// LastModifiedTime returns the latest modified time of all the sources. -func (c *client) LastModifiedTime(ctx context.Context) (_ time.Time, err error) { - defer derrors.Wrap(&err, "LastModifiedTime()") - var lmt time.Time - for _, s := range c.sources { - t, err := s.LastModifiedTime(ctx) - if err != nil { - return time.Time{}, err - } - if t.After(lmt) { - lmt = t - } - } - return lmt, nil -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/binary_118.go b/vendor/golang.org/x/vuln/cmd/govulncheck/binary_118.go deleted file mode 100644 index 6c13fb79e..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/binary_118.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package main - -import ( - "context" - "io" - - "golang.org/x/vuln/vulncheck" -) - -func binary(ctx context.Context, exe io.ReaderAt, cfg *vulncheck.Config) (_ *vulncheck.Result, err error) { - return vulncheck.Binary(ctx, exe, cfg) -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/binary_not118.go b/vendor/golang.org/x/vuln/cmd/govulncheck/binary_not118.go deleted file mode 100644 index 04bd8a6da..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/binary_not118.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package main - -import ( - "context" - "errors" - "io" - - "golang.org/x/vuln/vulncheck" -) - -func binary(ctx context.Context, exe io.ReaderAt, cfg *vulncheck.Config) (_ *vulncheck.Result, err error) { - return nil, errors.New("compile with Go 1.18 or higher to analyze binary files") -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/doc.go b/vendor/golang.org/x/vuln/cmd/govulncheck/doc.go index c65e8ccd8..ac738656b 100644 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/doc.go +++ b/vendor/golang.org/x/vuln/cmd/govulncheck/doc.go @@ -10,9 +10,9 @@ only those that could affect the application. By default, govulncheck makes requests to the Go vulnerability database at https://vuln.go.dev. Requests to the vulnerability database contain only module paths, not code or other properties of your program. See -https://vuln.go.dev/privacy.html for more. Set the GOVULNDB environment -variable to specify a different database, which must implement the -specification at https://go.dev/security/vuln/database. +https://vuln.go.dev/privacy.html for more. Use the -db flag to specify a +different database, which must implement the specification at +https://go.dev/security/vuln/database. Govulncheck looks for vulnerabilities in Go programs using a specific build configuration. For analyzing source code, that configuration is the Go version @@ -37,61 +37,52 @@ For example, it might say main.go:[line]:[column]: mypackage.main calls golang.org/x/text/language.Parse -For a more detailed call path that resembles Go panic stack traces, use the -v flag. - To control which files are processed, use the -tags flag to provide a comma-separated list of build tags, and the -test flag to indicate that test files should be included. -To run govulncheck on a compiled binary, pass it the path to the binary file: +To include more detailed stack traces, pass -show=traces, this will cause it to +print the full call stack for each entry. + +To run govulncheck on a compiled binary, pass it the path to the binary file +with the -mode=binary flag: - $ govulncheck $HOME/go/bin/my-go-program + $ govulncheck -mode=binary $HOME/go/bin/my-go-program Govulncheck uses the binary's symbol information to find mentions of vulnerable functions. Its output omits call stacks, which require source code analysis. +Govulncheck also supports -mode=extract on a Go binary for extraction of minimal +information needed to analyze the binary. This will produce a blob, typically much +smaller than the binary, that can also be passed to govulncheck as an argument with +-mode=binary. The users should not rely on the contents or representation of the blob. + Govulncheck exits successfully (exit code 0) if there are no vulnerabilities, -and exits unsuccessfully if there are. It also exits successfully if -json flag +and exits unsuccessfully if there are. It also exits successfully if the -json flag is provided, regardless of the number of detected vulnerabilities. -# Flags - -A few flags control govulncheck's behavior. - -The -v flag causes govulncheck to output more information about call stacks -when run on source. It has no effect when run on a binary. - -The -json flag causes govulncheck to print its output as a JSON object -corresponding to the type [golang.org/x/vuln/vulncheck.Result]. The exit code -of govulncheck is 0 when this flag is provided. - -The -tags flag accepts a comma-separated list of build tags to control which -files should be included in loaded packages for source analysis. - -The -test flag causes govulncheck to include test files in the source analysis. +Govulncheck supports streaming JSON. For more details, please see [golang.org/x/vuln/internal/govulncheck]. # Limitations -Govulncheck uses [golang.org/x/vuln/vulncheck], which has these limitations: +Govulncheck has these limitations: - Govulncheck analyzes function pointer and interface calls conservatively, which may result in false positives or inaccurate call stacks in some cases. - Calls to functions made using package reflect are not visible to static analysis. Vulnerable code reachable only through those calls will not be - reported. + reported. Use of the unsafe package may result in false negatives. - Because Go binaries do not contain detailed call information, govulncheck cannot show the call graphs for detected vulnerabilities. It may also report false positives for code that is in the binary but unreachable. - - There is no support for silencing vulnerability findings. + - There is no support for silencing vulnerability findings. See https://go.dev/issue/61211 for + updates. - Govulncheck only reads binaries compiled with Go 1.18 and later. - - Govulncheck only reports vulnerabilities that apply to the current Go - version. For example, a standard library vulnerability that only applies for - Go 1.18 will not be reported if the current Go version is 1.19. See - https://go.dev/issue/54841 for updates to this limitation. + - For binaries where the symbol information cannot be extracted, govulncheck + reports vulnerabilities for all modules on which the binary depends. # Feedback -Govulncheck is an experimental tool under active development. To share -feedback, see https://go.dev/security/vuln#feedback. +To share feedback, see https://go.dev/security/vuln#feedback. */ package main diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/errors.go b/vendor/golang.org/x/vuln/cmd/govulncheck/errors.go deleted file mode 100644 index 3008df06f..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/errors.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2022 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 main - -import ( - "errors" - "os" -) - -const noGoModErrorMessage = `govulncheck: no go.mod file - -govulncheck only works Go with modules. To make your project a module, run go mod init. - -See https://go.dev/doc/modules/managing-dependencies for more information.` - -const noGoSumErrorMessage = `govulncheck: no go.sum file - -Your module is missing a go.sum file. Try running go mod tidy. - -See https://go.dev/doc/modules/managing-dependencies for more information.` - -// fileExists checks if file path exists. Returns true -// if the file exists or it cannot prove that it does -// not exist. Otherwise, returns false. -func fileExists(path string) bool { - if _, err := os.Stat(path); err == nil { - return true - } else if errors.Is(err, os.ErrNotExist) { - return false - } - // Conservatively return true if os.Stat fails - // for some other reason. - return true -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/formatting.go b/vendor/golang.org/x/vuln/cmd/govulncheck/formatting.go deleted file mode 100644 index 10814a402..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/formatting.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2022 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 main - -import ( - "bytes" - "fmt" - "io" - "strings" -) - -// wrap wraps s to fit in maxWidth by breaking it into lines at whitespace. If a -// single word is longer than maxWidth, it is retained as its own line. -func wrap(s string, maxWidth int) string { - var b strings.Builder - w := 0 - - for _, f := range strings.Fields(s) { - if w > 0 && w+len(f)+1 > maxWidth { - b.WriteByte('\n') - w = 0 - } - if w != 0 { - b.WriteByte(' ') - w++ - } - b.WriteString(f) - w += len(f) - } - return b.String() -} - -type table struct { - headings []string - lines [][]string -} - -func newTable(headings ...string) *table { - return &table{headings: headings} -} - -func (t *table) row(cells ...string) { - // Split each cell into lines. - // Track the max number of lines. - var cls [][]string - max := 0 - for _, c := range cells { - ls := strings.Split(c, "\n") - if len(ls) > max { - max = len(ls) - } - cls = append(cls, ls) - } - // Add each line to the table. - for i := 0; i < max; i++ { - var line []string - for _, cl := range cls { - if i >= len(cl) { - line = append(line, "") - } else { - line = append(line, cl[i]) - } - } - t.lines = append(t.lines, line) - } -} - -func (t *table) write(w io.Writer) (err error) { - // Calculate column widths. - widths := make([]int, len(t.headings)) - for i, h := range t.headings { - widths[i] = len(h) - } - for _, l := range t.lines { - for i, c := range l { - if len(c) > widths[i] { - widths[i] = len(c) - } - } - } - - totalWidth := 0 - for _, w := range widths { - totalWidth += w - } - // Account for a space between columns. - totalWidth += len(widths) - 1 - dashes := strings.Repeat("-", totalWidth) - - writeLine := func(s string) { - if err == nil { - _, err = io.WriteString(w, s) - } - if err == nil { - _, err = io.WriteString(w, "\n") - } - } - - writeCells := func(cells []string) { - var buf bytes.Buffer - for i, c := range cells { - if i > 0 { - buf.WriteByte(' ') - } - fmt.Fprintf(&buf, "%-*s", widths[i], c) - } - writeLine(strings.TrimRight(buf.String(), " ")) - } - - // Write headings. - writeLine(dashes) - writeCells(t.headings) - writeLine(dashes) - - // Write body. - for _, l := range t.lines { - writeCells(l) - } - return err -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/cache.go b/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/cache.go deleted file mode 100644 index 5ce73e41e..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/cache.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2021 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 govulncheck supports the govulncheck command. -package govulncheck - -import ( - "encoding/json" - "go/build" - "os" - "path/filepath" - "sync" - "time" - - "golang.org/x/vuln/client" - "golang.org/x/vuln/osv" -) - -// The cache uses a single JSON index file for each vulnerability database -// which contains the map from packages to the time the last -// vulnerability for that package was added/modified and the time that -// the index was retrieved from the vulnerability database. The JSON -// format is as follows: -// -// $GOPATH/pkg/mod/cache/download/vulndb/{db hostname}/indexes/index.json -// { -// Retrieved time.Time -// Index client.DBIndex -// } -// -// Each package also has a JSON file which contains the array of vulnerability -// entries for the package. The JSON format is as follows: -// -// $GOPATH/pkg/mod/cache/download/vulndb/{db hostname}/{import path}/vulns.json -// []*osv.Entry - -// FSCache is a thread-safe file-system cache implementing osv.Cache -// -// TODO: use something like cmd/go/internal/lockedfile for thread safety? -type FSCache struct { - mu sync.Mutex - rootDir string -} - -// Assert that *FSCache implements client.Cache. -var _ client.Cache = (*FSCache)(nil) - -// use cfg.GOMODCACHE available in cmd/go/internal? -var defaultCacheRoot = filepath.Join(build.Default.GOPATH, "/pkg/mod/cache/download/vulndb") - -func DefaultCache() *FSCache { - return &FSCache{rootDir: defaultCacheRoot} -} - -type cachedIndex struct { - Retrieved time.Time - Index client.DBIndex -} - -func (c *FSCache) ReadIndex(dbName string) (client.DBIndex, time.Time, error) { - c.mu.Lock() - defer c.mu.Unlock() - - b, err := os.ReadFile(filepath.Join(c.rootDir, dbName, "index.json")) - if err != nil { - if os.IsNotExist(err) { - return nil, time.Time{}, nil - } - return nil, time.Time{}, err - } - var index cachedIndex - if err := json.Unmarshal(b, &index); err != nil { - return nil, time.Time{}, err - } - return index.Index, index.Retrieved, nil -} - -func (c *FSCache) WriteIndex(dbName string, index client.DBIndex, retrieved time.Time) error { - c.mu.Lock() - defer c.mu.Unlock() - - path := filepath.Join(c.rootDir, dbName) - if err := os.MkdirAll(path, 0755); err != nil { - return err - } - j, err := json.Marshal(cachedIndex{ - Index: index, - Retrieved: retrieved, - }) - if err != nil { - return err - } - if err := os.WriteFile(filepath.Join(path, "index.json"), j, 0666); err != nil { - return err - } - return nil -} - -func (c *FSCache) ReadEntries(dbName string, p string) ([]*osv.Entry, error) { - c.mu.Lock() - defer c.mu.Unlock() - - ep, err := client.EscapeModulePath(p) - if err != nil { - return nil, err - } - b, err := os.ReadFile(filepath.Join(c.rootDir, dbName, ep, "vulns.json")) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - var entries []*osv.Entry - if err := json.Unmarshal(b, &entries); err != nil { - return nil, err - } - return entries, nil -} - -func (c *FSCache) WriteEntries(dbName string, p string, entries []*osv.Entry) error { - c.mu.Lock() - defer c.mu.Unlock() - - ep, err := client.EscapeModulePath(p) - if err != nil { - return err - } - path := filepath.Join(c.rootDir, dbName, ep) - if err := os.MkdirAll(path, 0777); err != nil { - return err - } - j, err := json.Marshal(entries) - if err != nil { - return err - } - if err := os.WriteFile(filepath.Join(path, "vulns.json"), j, 0666); err != nil { - return err - } - return nil -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/source.go b/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/source.go deleted file mode 100644 index 8b6f6549b..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/source.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2022 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 govulncheck - -import ( - "fmt" - "sort" - "strings" - - "golang.org/x/tools/go/packages" - "golang.org/x/vuln/vulncheck" -) - -// A PackageError contains errors from loading a set of packages. -type PackageError struct { - Errors []packages.Error -} - -func (e *PackageError) Error() string { - var b strings.Builder - fmt.Fprintln(&b, "Packages contain errors:") - for _, e := range e.Errors { - fmt.Fprintln(&b, e) - } - return b.String() -} - -// LoadPackages loads the packages matching patterns using cfg, after setting -// the cfg mode flags that vulncheck needs for analysis. -// If the packages contain errors, a PackageError is returned containing a list of the errors, -// along with the packages themselves. -func LoadPackages(cfg *packages.Config, patterns ...string) ([]*vulncheck.Package, error) { - cfg.Mode |= packages.NeedName | packages.NeedImports | packages.NeedTypes | - packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps | - packages.NeedModule - - pkgs, err := packages.Load(cfg, patterns...) - vpkgs := vulncheck.Convert(pkgs) - if err != nil { - return nil, err - } - var perrs []packages.Error - packages.Visit(pkgs, nil, func(p *packages.Package) { - perrs = append(perrs, p.Errors...) - }) - if len(perrs) > 0 { - err = &PackageError{perrs} - } - return vpkgs, err -} - -// CallInfo is information about calls to vulnerable functions. -type CallInfo struct { - // CallStacks contains all call stacks to vulnerable functions. - CallStacks map[*vulncheck.Vuln][]vulncheck.CallStack - - // VulnGroups contains vulnerabilities grouped by ID and package. - VulnGroups [][]*vulncheck.Vuln - - // ModuleVersions is a map of module paths to versions. - ModuleVersions map[string]string - - // TopPackages contains the top-level packages in the call info. - TopPackages map[string]bool -} - -// GetCallInfo computes call stacks and related information from a vulncheck.Result. -// It also makes a set of top-level packages from pkgs. -func GetCallInfo(r *vulncheck.Result, pkgs []*vulncheck.Package) *CallInfo { - pset := map[string]bool{} - for _, p := range pkgs { - pset[p.PkgPath] = true - } - return &CallInfo{ - CallStacks: vulncheck.CallStacks(r), - VulnGroups: groupByIDAndPackage(r.Vulns), - ModuleVersions: moduleVersionMap(r.Modules), - TopPackages: pset, - } -} - -func groupByIDAndPackage(vs []*vulncheck.Vuln) [][]*vulncheck.Vuln { - groups := map[[2]string][]*vulncheck.Vuln{} - for _, v := range vs { - key := [2]string{v.OSV.ID, v.PkgPath} - groups[key] = append(groups[key], v) - } - - var res [][]*vulncheck.Vuln - for _, g := range groups { - res = append(res, g) - } - sort.Slice(res, func(i, j int) bool { - return res[i][0].PkgPath < res[j][0].PkgPath - }) - return res -} - -// moduleVersionMap builds a map from module paths to versions. -func moduleVersionMap(mods []*vulncheck.Module) map[string]string { - moduleVersions := map[string]string{} - for _, m := range mods { - v := m.Version - if m.Replace != nil { - v = m.Replace.Version - } - moduleVersions[m.Path] = v - } - return moduleVersions -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/util.go b/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/util.go deleted file mode 100644 index 17cc23ca2..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/util.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2022 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 govulncheck - -import ( - "fmt" - "strings" - - "golang.org/x/mod/semver" - isem "golang.org/x/vuln/internal/semver" - "golang.org/x/vuln/osv" - "golang.org/x/vuln/vulncheck" -) - -// LatestFixed returns the latest fixed version in the list of affected ranges, -// or the empty string if there are no fixed versions. -func LatestFixed(as []osv.Affected) string { - v := "" - for _, a := range as { - for _, r := range a.Ranges { - if r.Type == osv.TypeSemver { - for _, e := range r.Events { - if e.Fixed != "" && (v == "" || - semver.Compare(isem.CanonicalizeSemverPrefix(e.Fixed), isem.CanonicalizeSemverPrefix(v)) > 0) { - v = e.Fixed - } - } - } - } - } - return v -} - -// SummarizeCallStack returns a short description of the call stack. -// It uses one of two forms, depending on what the lowest function F in topPkgs -// calls: -// - If it calls a function V from the vulnerable package, then summarizeCallStack -// returns "F calls V". -// - If it calls a function G in some other package, which eventually calls V, -// it returns "F calls G, which eventually calls V". -// -// If it can't find any of these functions, summarizeCallStack returns the empty string. -func SummarizeCallStack(cs vulncheck.CallStack, topPkgs map[string]bool, vulnPkg string) string { - // Find the lowest function in the top packages. - iTop := lowest(cs, func(e vulncheck.StackEntry) bool { - return topPkgs[PkgPath(e.Function)] - }) - if iTop < 0 { - return "" - } - // Find the highest function in the vulnerable package that is below iTop. - iVuln := highest(cs[iTop+1:], func(e vulncheck.StackEntry) bool { - return PkgPath(e.Function) == vulnPkg - }) - if iVuln < 0 { - return "" - } - iVuln += iTop + 1 // adjust for slice in call to highest. - topName := FuncName(cs[iTop].Function) - topPos := AbsRelShorter(FuncPos(cs[iTop].Call)) - if topPos != "" { - topPos += ": " - } - vulnName := FuncName(cs[iVuln].Function) - if iVuln == iTop+1 { - return fmt.Sprintf("%s%s calls %s", topPos, topName, vulnName) - } - return fmt.Sprintf("%s%s calls %s, which eventually calls %s", - topPos, topName, FuncName(cs[iTop+1].Function), vulnName) -} - -// highest returns the highest (one with the smallest index) entry in the call -// stack for which f returns true. -func highest(cs vulncheck.CallStack, f func(e vulncheck.StackEntry) bool) int { - for i := 0; i < len(cs); i++ { - if f(cs[i]) { - return i - } - } - return -1 -} - -// lowest returns the lowest (one with the largets index) entry in the call -// stack for which f returns true. -func lowest(cs vulncheck.CallStack, f func(e vulncheck.StackEntry) bool) int { - for i := len(cs) - 1; i >= 0; i-- { - if f(cs[i]) { - return i - } - } - return -1 -} - -// PkgPath returns the package path from fn. -func PkgPath(fn *vulncheck.FuncNode) string { - if fn.PkgPath != "" { - return fn.PkgPath - } - s := strings.TrimPrefix(fn.RecvType, "*") - if i := strings.LastIndexByte(s, '.'); i > 0 { - s = s[:i] - } - return s -} - -// FuncName returns the function name from fn, adjusted -// to remove pointer annotations. -func FuncName(fn *vulncheck.FuncNode) string { - return strings.TrimPrefix(fn.String(), "*") -} - -// FuncPos returns the function position from call. -func FuncPos(call *vulncheck.CallSite) string { - if call != nil && call.Pos != nil { - return call.Pos.String() - } - return "" -} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/main.go b/vendor/golang.org/x/vuln/cmd/govulncheck/main.go index 240d71941..f6ca253fe 100644 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/main.go +++ b/vendor/golang.org/x/vuln/cmd/govulncheck/main.go @@ -5,435 +5,27 @@ package main import ( - "bytes" "context" - "encoding/json" - "flag" "fmt" - "go/build" "os" - "os/exec" - "path/filepath" - "sort" - "strings" - "golang.org/x/exp/maps" - "golang.org/x/tools/go/buildutil" - "golang.org/x/tools/go/packages" - "golang.org/x/vuln/client" - "golang.org/x/vuln/cmd/govulncheck/internal/govulncheck" - "golang.org/x/vuln/osv" - "golang.org/x/vuln/vulncheck" + "golang.org/x/vuln/scan" ) -var ( - jsonFlag = flag.Bool("json", false, "output JSON") - verboseFlag = flag.Bool("v", false, "print a full call stack for each vulnerability") - testFlag = flag.Bool("test", false, "analyze test files. Only valid for source code.") - dirFlag string -) - -func init() { - flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", - "comma-separated `list` of build tags") -} - func main() { - flag.Usage = func() { - fmt.Fprint(os.Stderr, `usage: - govulncheck [flags] package... - govulncheck [flags] binary - -`) - flag.PrintDefaults() - fmt.Fprintf(os.Stderr, ` -For details, see https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck. -`) - } - flag.Parse() - - if len(flag.Args()) == 0 { - flag.Usage() - os.Exit(1) - } - - dbs := []string{"https://vuln.go.dev"} - if GOVULNDB := os.Getenv("GOVULNDB"); GOVULNDB != "" { - dbs = strings.Split(GOVULNDB, ",") - } - dbClient, err := client.NewClient(dbs, client.Options{ - HTTPCache: govulncheck.DefaultCache(), - }) - if err != nil { - die("govulncheck: %s", err) - } - vcfg := &vulncheck.Config{Client: dbClient, SourceGoVersion: goVersion()} - - patterns := flag.Args() - if !*jsonFlag { - fmt.Printf(`govulncheck is an experimental tool. Share feedback at https://go.dev/s/govulncheck-feedback. - -Scanning for dependencies with known vulnerabilities... -`) - } - var ( - r *vulncheck.Result - pkgs []*vulncheck.Package - unaffected []*vulncheck.Vuln - ctx = context.Background() - ) - if len(patterns) == 1 && isFile(patterns[0]) { - if *testFlag { - die("govulncheck: the -test flag is invalid for binaries") - } - if build.Default.BuildTags != nil { - die("govulncheck: the -tags flag is invalid for binaries") - } - f, err := os.Open(patterns[0]) - if err != nil { - die("govulncheck: %v", err) - } - defer f.Close() - r, err = binary(ctx, f, vcfg) - if err != nil { - die("govulncheck: %v", err) - } - } else { - cfg := &packages.Config{ - Dir: filepath.FromSlash(dirFlag), - Tests: *testFlag, - BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(build.Default.BuildTags, ","))}, - } - pkgs, err = govulncheck.LoadPackages(cfg, patterns...) - if err != nil { - // Try to provide a meaningful and actionable error message. - if !fileExists(filepath.Join(dirFlag, "go.mod")) { - die(noGoModErrorMessage) - } else if !fileExists(filepath.Join(dirFlag, "go.sum")) { - die(noGoSumErrorMessage) - } - die("govulncheck: %v", err) - } - - // Sort pkgs so that the PkgNodes returned by vulncheck.Source will be - // deterministic. - sortPackages(pkgs) - r, err = vulncheck.Source(ctx, pkgs, vcfg) - if err != nil { - die("govulncheck: %v", err) - } - unaffected = filterUnaffected(r) - r.Vulns = filterCalled(r) - } - - if *jsonFlag { - // Following golang.org/x/tools/go/analysis/singlechecker, - // return 0 exit code in -json mode. - writeJSON(r) - os.Exit(0) - } - - // set of top-level packages, used to find representative symbols - ci := govulncheck.GetCallInfo(r, pkgs) - writeText(r, ci, unaffected) - - // Following golang.org/x/tools/go/analysis/singlechecker, - // fail with 3 if there are findings (in this case, vulns). - exitCode := 0 - if len(r.Vulns) > 0 { - exitCode = 3 - } - os.Exit(exitCode) -} - -// filterCalled returns vulnerabilities where the symbols are actually called. -func filterCalled(r *vulncheck.Result) []*vulncheck.Vuln { - var vulns []*vulncheck.Vuln - for _, v := range r.Vulns { - if v.CallSink != 0 { - vulns = append(vulns, v) - } - } - sortVulns(vulns) - return vulns -} - -// filterUnaffected returns vulnerabilities where no symbols are called, -// grouped by module. -func filterUnaffected(r *vulncheck.Result) []*vulncheck.Vuln { - // It is possible that the same vuln.OSV.ID has vuln.CallSink != 0 - // for one symbol, but vuln.CallSink == 0 for a different one, so - // we need to filter out ones that have been called. - called := filterCalled(r) - calledIDs := map[string]bool{} - for _, vuln := range called { - calledIDs[vuln.OSV.ID] = true - } - - idToVuln := map[string]*vulncheck.Vuln{} - for _, vuln := range r.Vulns { - if !calledIDs[vuln.OSV.ID] { - idToVuln[vuln.OSV.ID] = vuln - } - } - var output []*vulncheck.Vuln - for _, vuln := range idToVuln { - output = append(output, vuln) - } - sortVulns(output) - return output -} - -func sortVulns(vulns []*vulncheck.Vuln) { - sort.Slice(vulns, func(i, j int) bool { - return vulns[i].OSV.ID > vulns[j].OSV.ID - }) -} - -func sortPackages(pkgs []*vulncheck.Package) { - sort.Slice(pkgs, func(i, j int) bool { - return pkgs[i].PkgPath < pkgs[j].PkgPath - }) - for _, pkg := range pkgs { - sort.Slice(pkg.Imports, func(i, j int) bool { - return pkg.Imports[i].PkgPath < pkg.Imports[j].PkgPath - }) - } -} + ctx := context.Background() -func writeJSON(r *vulncheck.Result) { - b, err := json.MarshalIndent(r, "", "\t") - if err != nil { - die("govulncheck: %s", err) + cmd := scan.Command(ctx, os.Args[1:]...) + err := cmd.Start() + if err == nil { + err = cmd.Wait() } - os.Stdout.Write(b) - fmt.Println() -} - -const ( - labelWidth = 16 - lineLength = 55 -) - -func writeText(r *vulncheck.Result, ci *govulncheck.CallInfo, unaffected []*vulncheck.Vuln) { - uniqueVulns := map[string]bool{} - for _, v := range r.Vulns { - uniqueVulns[v.OSV.ID] = true - } - switch len(uniqueVulns) { - case 0: - fmt.Println("No vulnerabilities found.") - case 1: - fmt.Println("Found 1 known vulnerability.") + switch err := err.(type) { + case nil: + case interface{ ExitCode() int }: + os.Exit(err.ExitCode()) default: - fmt.Printf("Found %d known vulnerabilities.\n", len(uniqueVulns)) - } - for idx, vg := range ci.VulnGroups { - fmt.Println() - // All the vulns in vg have the same PkgPath, ModPath and OSV. - // All have a non-zero CallSink. - v0 := vg[0] - id := v0.OSV.ID - details := wrap(v0.OSV.Details, 80-labelWidth) - found := foundVersion(v0.ModPath, v0.PkgPath, ci) - fixed := fixedVersion(v0.PkgPath, v0.OSV.Affected) - - var stacks string - if !*verboseFlag { - stacks = defaultCallStacks(vg, ci) - } else { - stacks = verboseCallStacks(vg, ci) - } - var b strings.Builder - if len(stacks) > 0 { - b.WriteString(indent("\n\nCall stacks in your code:\n", 2)) - b.WriteString(indent(stacks, 6)) - } - writeVulnerability(idx+1, id, details, b.String(), found, fixed, platforms(v0.OSV)) - } - if len(unaffected) > 0 { - fmt.Printf(` -=== Informational === - -The vulnerabilities below are in packages that you import, but your code -doesn't appear to call any vulnerable functions. You may not need to take any -action. See https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck -for details. -`) - for idx, vuln := range unaffected { - found := foundVersion(vuln.ModPath, vuln.PkgPath, ci) - fixed := fixedVersion(vuln.PkgPath, vuln.OSV.Affected) - fmt.Println() - writeVulnerability(idx+1, vuln.OSV.ID, vuln.OSV.Details, "", found, fixed, platforms(vuln.OSV)) - } - } -} - -func writeVulnerability(idx int, id, details, callstack, found, fixed, platforms string) { - if fixed == "" { - fixed = "N/A" - } - if platforms != "" { - platforms = " Platforms: " + platforms + "\n" - } - fmt.Printf(`Vulnerability #%d: %s -%s%s - Found in: %s - Fixed in: %s -%s More info: https://pkg.go.dev/vuln/%s -`, idx, id, indent(details, 2), callstack, found, fixed, platforms, id) -} - -func foundVersion(modulePath, pkgPath string, ci *govulncheck.CallInfo) string { - var found string - if v := ci.ModuleVersions[modulePath]; v != "" { - found = packageVersionString(pkgPath, v[1:]) - } - return found -} - -func fixedVersion(pkgPath string, affected []osv.Affected) string { - fixed := govulncheck.LatestFixed(affected) - if fixed != "" { - fixed = packageVersionString(pkgPath, fixed) - } - return fixed -} - -func defaultCallStacks(vg []*vulncheck.Vuln, ci *govulncheck.CallInfo) string { - var summaries []string - for _, v := range vg { - if css := ci.CallStacks[v]; len(css) > 0 { - if sum := govulncheck.SummarizeCallStack(css[0], ci.TopPackages, v.PkgPath); sum != "" { - summaries = append(summaries, strings.TrimSpace(sum)) - } - } - } - if len(summaries) > 0 { - sort.Strings(summaries) - summaries = compact(summaries) - } - var b strings.Builder - for _, s := range summaries { - b.WriteString(s) - b.WriteString("\n") - } - return b.String() -} - -func verboseCallStacks(vg []*vulncheck.Vuln, ci *govulncheck.CallInfo) string { - // Display one full call stack for each vuln. - i := 1 - nMore := 0 - var b strings.Builder - for _, v := range vg { - css := ci.CallStacks[v] - if len(css) == 0 { - continue - } - b.WriteString(fmt.Sprintf("#%d: for function %s\n", i, v.Symbol)) - for _, e := range css[0] { - b.WriteString(fmt.Sprintf(" %s\n", govulncheck.FuncName(e.Function))) - if pos := govulncheck.AbsRelShorter(govulncheck.FuncPos(e.Call)); pos != "" { - b.WriteString(fmt.Sprintf(" %s\n", pos)) - } - } - i++ - nMore += len(css) - 1 - } - if nMore > 0 { - b.WriteString(fmt.Sprintf(" There are %d more call stacks available.\n", nMore)) - b.WriteString(fmt.Sprintf("To see all of them, pass the -json flags.\n")) - } - return b.String() -} - -// platforms returns a string describing the GOOS/GOARCH pairs that the vuln affects. -// If it affects all of them, it returns the empty string. -func platforms(e *osv.Entry) string { - platforms := map[string]bool{} - for _, a := range e.Affected { - for _, p := range a.EcosystemSpecific.Imports { - for _, os := range p.GOOS { - for _, arch := range p.GOARCH { - platforms[os+"/"+arch] = true - } - } - } - } - keys := maps.Keys(platforms) - sort.Strings(keys) - return strings.Join(keys, ", ") -} - -func isFile(path string) bool { - s, err := os.Stat(path) - if err != nil { - return false - } - return !s.IsDir() -} - -// compact replaces consecutive runs of equal elements with a single copy. -// This is like the uniq command found on Unix. -// compact modifies the contents of the slice s; it does not create a new slice. -// -// Modified (generics removed) from exp/slices/slices.go. -func compact(s []string) []string { - if len(s) == 0 { - return s - } - i := 1 - last := s[0] - for _, v := range s[1:] { - if v != last { - s[i] = v - i++ - last = v - } - } - return s[:i] -} - -func goVersion() string { - if v := os.Getenv("GOVERSION"); v != "" { - // Unlikely to happen in practice, mostly used for testing. - return v - } - out, err := exec.Command("go", "env", "GOVERSION").Output() - if err != nil { - fmt.Fprintf(os.Stderr, "failed to determine go version; skipping stdlib scanning: %v\n", err) - return "" - } - return string(bytes.TrimSpace(out)) -} - -func packageVersionString(packagePath, version string) string { - v := "v" + version - if importPathInStdlib(packagePath) { - v = semverToGoTag(v) - } - return fmt.Sprintf("%s@%s", packagePath, v) -} - -func die(format string, args ...interface{}) { - fmt.Fprintf(os.Stderr, format+"\n", args...) - os.Exit(1) -} - -// indent returns the output of prefixing n spaces to s at every line break, -// except for empty lines. See TestIndent for examples. -func indent(s string, n int) string { - b := []byte(s) - var result []byte - shouldAppend := true - prefix := strings.Repeat(" ", n) - for _, c := range b { - if shouldAppend && c != '\n' { - result = append(result, prefix...) - } - result = append(result, c) - shouldAppend = c == '\n' + fmt.Fprintln(os.Stderr, err) + os.Exit(1) } - return string(result) } diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/main_testmode.go b/vendor/golang.org/x/vuln/cmd/govulncheck/main_testmode.go deleted file mode 100644 index 0ac803b89..000000000 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/main_testmode.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build testmode - -package main - -import "flag" - -func init() { - flag.StringVar(&dirFlag, "dir", "", "directory to use for loading source files") -} diff --git a/vendor/golang.org/x/vuln/internal/buildinfo/README.md b/vendor/golang.org/x/vuln/internal/buildinfo/README.md new file mode 100644 index 000000000..f04bedd89 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/buildinfo/README.md @@ -0,0 +1,9 @@ +This code is a copied and slightly modified subset of go/src/debug/buildinfo. + +It contains logic for parsing Go binary files for the purpose of extracting +module dependency and symbol table information. + +Logic added by vulncheck is located in files with "additions_" prefix. + +Within the originally named files, changed or added logic is annotated with +a comment starting with "Addition:". diff --git a/vendor/golang.org/x/vuln/internal/buildinfo/additions_buildinfo.go b/vendor/golang.org/x/vuln/internal/buildinfo/additions_buildinfo.go new file mode 100644 index 000000000..642920be1 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/buildinfo/additions_buildinfo.go @@ -0,0 +1,257 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.18 +// +build go1.18 + +package buildinfo + +// This file adds to buildinfo the functionality for extracting the PCLN table. + +import ( + "debug/elf" + "debug/macho" + "debug/pe" + "encoding/binary" + "errors" + "fmt" + "io" +) + +// ErrNoSymbols represents non-existence of symbol +// table in binaries supported by buildinfo. +var ErrNoSymbols = errors.New("no symbol section") + +// SymbolInfo is derived from cmd/internal/objfile/elf.go:symbols, symbolData. +func (x *elfExe) SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) { + sym, err := x.lookupSymbol(name) + if err != nil { + if errors.Is(err, elf.ErrNoSymbols) { + return 0, 0, nil, ErrNoSymbols + } + return 0, 0, nil, fmt.Errorf("no symbol %q", name) + } + prog := x.progContaining(sym.Value) + if prog == nil { + return 0, 0, nil, fmt.Errorf("no Prog containing value %d for %q", sym.Value, name) + } + return sym.Value, prog.Vaddr, prog.ReaderAt, nil +} + +func (x *elfExe) lookupSymbol(name string) (*elf.Symbol, error) { + x.symbolsOnce.Do(func() { + syms, err := x.f.Symbols() + if err != nil { + x.symbolsErr = err + return + } + x.symbols = make(map[string]*elf.Symbol, len(syms)) + for _, s := range syms { + s := s // make a copy to prevent aliasing + x.symbols[s.Name] = &s + } + }) + if x.symbolsErr != nil { + return nil, x.symbolsErr + } + return x.symbols[name], nil +} + +func (x *elfExe) progContaining(addr uint64) *elf.Prog { + for _, p := range x.f.Progs { + if addr >= p.Vaddr && addr < p.Vaddr+p.Filesz { + return p + } + } + return nil +} + +const go12magic = 0xfffffffb +const go116magic = 0xfffffffa + +// PCLNTab is derived from cmd/internal/objfile/elf.go:pcln. +func (x *elfExe) PCLNTab() ([]byte, uint64) { + var offset uint64 + text := x.f.Section(".text") + if text != nil { + offset = text.Offset + } + pclntab := x.f.Section(".gopclntab") + if pclntab == nil { + // Addition: this code is added to support some form of stripping. + pclntab = x.f.Section(".data.rel.ro.gopclntab") + if pclntab == nil { + pclntab = x.f.Section(".data.rel.ro") + if pclntab == nil { + return nil, 0 + } + // Possibly the PCLN table has been stuck in the .data.rel.ro section, but without + // its own section header. We can search for for the start by looking for the four + // byte magic and the go magic. + b, err := pclntab.Data() + if err != nil { + return nil, 0 + } + // TODO(rolandshoemaker): I'm not sure if the 16 byte increment during the search is + // actually correct. During testing it worked, but that may be because I got lucky + // with the binary I was using, and we need to do four byte jumps to exhaustively + // search the section? + for i := 0; i < len(b); i += 16 { + if len(b)-i > 16 && b[i+4] == 0 && b[i+5] == 0 && + (b[i+6] == 1 || b[i+6] == 2 || b[i+6] == 4) && + (b[i+7] == 4 || b[i+7] == 8) { + // Also check for the go magic + leMagic := binary.LittleEndian.Uint32(b[i:]) + beMagic := binary.BigEndian.Uint32(b[i:]) + switch { + case leMagic == go12magic: + fallthrough + case beMagic == go12magic: + fallthrough + case leMagic == go116magic: + fallthrough + case beMagic == go116magic: + return b[i:], offset + } + } + } + } + } + b, err := pclntab.Data() + if err != nil { + return nil, 0 + } + return b, offset +} + +// SymbolInfo is derived from cmd/internal/objfile/pe.go:findPESymbol, loadPETable. +func (x *peExe) SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) { + sym, err := x.lookupSymbol(name) + if err != nil { + return 0, 0, nil, err + } + if sym == nil { + return 0, 0, nil, fmt.Errorf("no symbol %q", name) + } + sect := x.f.Sections[sym.SectionNumber-1] + // In PE, the symbol's value is the offset from the section start. + return uint64(sym.Value), 0, sect.ReaderAt, nil +} + +func (x *peExe) lookupSymbol(name string) (*pe.Symbol, error) { + x.symbolsOnce.Do(func() { + x.symbols = make(map[string]*pe.Symbol, len(x.f.Symbols)) + if len(x.f.Symbols) == 0 { + x.symbolsErr = ErrNoSymbols + return + } + for _, s := range x.f.Symbols { + x.symbols[s.Name] = s + } + }) + if x.symbolsErr != nil { + return nil, x.symbolsErr + } + return x.symbols[name], nil +} + +// PCLNTab is derived from cmd/internal/objfile/pe.go:pcln. +// Assumes that the underlying symbol table exists, otherwise +// it might panic. +func (x *peExe) PCLNTab() ([]byte, uint64) { + var textOffset uint64 + for _, section := range x.f.Sections { + if section.Name == ".text" { + textOffset = uint64(section.Offset) + break + } + } + + var start, end int64 + var section int + if s, _ := x.lookupSymbol("runtime.pclntab"); s != nil { + start = int64(s.Value) + section = int(s.SectionNumber - 1) + } + if s, _ := x.lookupSymbol("runtime.epclntab"); s != nil { + end = int64(s.Value) + } + if start == 0 || end == 0 { + return nil, 0 + } + offset := int64(x.f.Sections[section].Offset) + start + size := end - start + + pclntab := make([]byte, size) + if _, err := x.r.ReadAt(pclntab, offset); err != nil { + return nil, 0 + } + return pclntab, textOffset +} + +// SymbolInfo is derived from cmd/internal/objfile/macho.go:symbols. +func (x *machoExe) SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) { + sym, err := x.lookupSymbol(name) + if err != nil { + return 0, 0, nil, err + } + if sym == nil { + return 0, 0, nil, fmt.Errorf("no symbol %q", name) + } + seg := x.segmentContaining(sym.Value) + if seg == nil { + return 0, 0, nil, fmt.Errorf("no Segment containing value %d for %q", sym.Value, name) + } + return sym.Value, seg.Addr, seg.ReaderAt, nil +} + +func (x *machoExe) lookupSymbol(name string) (*macho.Symbol, error) { + const mustExistSymbol = "runtime.main" + x.symbolsOnce.Do(func() { + x.symbols = make(map[string]*macho.Symbol, len(x.f.Symtab.Syms)) + for _, s := range x.f.Symtab.Syms { + s := s // make a copy to prevent aliasing + x.symbols[s.Name] = &s + } + // In the presence of stripping, the symbol table for darwin + // binaries will not be empty, but the program symbols will + // be missing. + if _, ok := x.symbols[mustExistSymbol]; !ok { + x.symbolsErr = ErrNoSymbols + } + }) + + if x.symbolsErr != nil { + return nil, x.symbolsErr + } + return x.symbols[name], nil +} + +func (x *machoExe) segmentContaining(addr uint64) *macho.Segment { + for _, load := range x.f.Loads { + seg, ok := load.(*macho.Segment) + if ok && seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 && seg.Name != "__PAGEZERO" { + return seg + } + } + return nil +} + +// SymbolInfo is derived from cmd/internal/objfile/macho.go:pcln. +func (x *machoExe) PCLNTab() ([]byte, uint64) { + var textOffset uint64 + text := x.f.Section("__text") + if text != nil { + textOffset = uint64(text.Offset) + } + pclntab := x.f.Section("__gopclntab") + if pclntab == nil { + return nil, 0 + } + b, err := pclntab.Data() + if err != nil { + return nil, 0 + } + return b, textOffset +} diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/binscan/scan.go b/vendor/golang.org/x/vuln/internal/buildinfo/additions_scan.go similarity index 65% rename from vendor/golang.org/x/vuln/vulncheck/internal/binscan/scan.go rename to vendor/golang.org/x/vuln/internal/buildinfo/additions_scan.go index c39cec4a3..c5d267998 100644 --- a/vendor/golang.org/x/vuln/vulncheck/internal/binscan/scan.go +++ b/vendor/golang.org/x/vuln/internal/buildinfo/additions_scan.go @@ -5,9 +5,7 @@ //go:build go1.18 // +build go1.18 -// Package binscan contains methods for parsing Go binary files for the purpose -// of extracting module dependency and symbol table information. -package binscan +package buildinfo // Code in this package is dervied from src/cmd/go/internal/version/version.go // and cmd/go/internal/version/exe.go. @@ -22,7 +20,7 @@ import ( "strings" "golang.org/x/tools/go/packages" - "golang.org/x/vuln/vulncheck/internal/gosym" + "golang.org/x/vuln/internal/gosym" ) func debugModulesToPackagesModules(debugModules []*debug.Module) []*packages.Module { @@ -42,10 +40,17 @@ func debugModulesToPackagesModules(debugModules []*debug.Module) []*packages.Mod return packagesModules } -// ExtractPackagesAndSymbols extracts the symbols, packages, their -// associated module versions from a Go binary, and Go version used -// to build the binary. -func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, map[string][]string, *debug.BuildInfo, error) { +type Symbol struct { + Pkg string `json:"pkg,omitempty"` + Name string `json:"name,omitempty"` +} + +// ExtractPackagesAndSymbols extracts symbols, packages, modules from +// bin as well as bin's metadata. +// +// If the symbol table is not available, such as in the case of stripped +// binaries, returns module and binary info but without the symbol info. +func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, []Symbol, *debug.BuildInfo, error) { bi, err := buildinfo.Read(bin) if err != nil { return nil, nil, nil, err @@ -53,7 +58,7 @@ func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, map[string] funcSymName := gosym.FuncSymName(bi.GoVersion) if funcSymName == "" { - return nil, nil, nil, fmt.Errorf("binary built using unsupported Go Version: %v", bi.GoVersion) + return nil, nil, nil, fmt.Errorf("binary built using unsupported Go version: %q", bi.GoVersion) } x, err := openExe(bin) @@ -61,11 +66,20 @@ func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, map[string] return nil, nil, nil, err } + value, base, r, err := x.SymbolInfo(funcSymName) + if err != nil { + if errors.Is(err, ErrNoSymbols) { + // bin is stripped, so return just module info and metadata. + return debugModulesToPackagesModules(bi.Deps), nil, bi, nil + } + return nil, nil, nil, fmt.Errorf("reading %v: %v", funcSymName, err) + } + pclntab, textOffset := x.PCLNTab() if pclntab == nil { - // TODO(roland): if we have build information, but not PCLN table, we should be able to - // fall back to much higher granularity vulnerability checking. - return nil, nil, nil, errors.New("unable to load the PCLN table") + // If we have build information, but not PCLN table, fall + // back to much higher granularity vulnerability checking. + return debugModulesToPackagesModules(bi.Deps), nil, bi, nil } lineTab := gosym.NewLineTable(pclntab, textOffset) if lineTab == nil { @@ -76,7 +90,7 @@ func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, map[string] return nil, nil, nil, err } - packageSymbols := map[string][]string{} + pkgSyms := make(map[Symbol]bool) for _, f := range tab.Funcs { if f.Func == nil { continue @@ -85,11 +99,9 @@ func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, map[string] if err != nil { return nil, nil, nil, err } - packageSymbols[pkgName] = append(packageSymbols[pkgName], symName) - value, base, r, err := x.SymbolInfo(funcSymName) - if err != nil { - return nil, nil, nil, fmt.Errorf("reading %v: %v", funcSymName, err) - } + pkgSyms[Symbol{pkgName, symName}] = true + + // Collect symbols that were inlined in f. it, err := lineTab.InlineTree(&f, value, base, r) if err != nil { return nil, nil, nil, fmt.Errorf("InlineTree: %v", err) @@ -99,11 +111,16 @@ func ExtractPackagesAndSymbols(bin io.ReaderAt) ([]*packages.Module, map[string] if err != nil { return nil, nil, nil, err } - packageSymbols[pkgName] = append(packageSymbols[pkgName], symName) + pkgSyms[Symbol{pkgName, symName}] = true } } - return debugModulesToPackagesModules(bi.Deps), packageSymbols, bi, nil + var syms []Symbol + for ps := range pkgSyms { + syms = append(syms, ps) + } + + return debugModulesToPackagesModules(bi.Deps), syms, bi, nil } func parseName(s *gosym.Sym) (pkg, sym string, err error) { diff --git a/vendor/golang.org/x/vuln/internal/buildinfo/buildinfo.go b/vendor/golang.org/x/vuln/internal/buildinfo/buildinfo.go new file mode 100644 index 000000000..f29dffa21 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/buildinfo/buildinfo.go @@ -0,0 +1,221 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.18 +// +build go1.18 + +package buildinfo + +// Addition: this file is a trimmed and slightly modified version of debug/buildinfo/buildinfo.go + +import ( + "bytes" + "debug/elf" + "debug/macho" + "debug/pe" + "fmt" + "sync" + + // "internal/xcoff" + "io" +) + +// Addition: modification of rawBuildInfo in the original file. +// openExe returns reader r as an exe. +func openExe(r io.ReaderAt) (exe, error) { + data := make([]byte, 16) + if _, err := r.ReadAt(data, 0); err != nil { + return nil, err + } + if bytes.HasPrefix(data, []byte("\x7FELF")) { + e, err := elf.NewFile(r) + if err != nil { + return nil, err + } + return &elfExe{f: e}, nil + } + if bytes.HasPrefix(data, []byte("MZ")) { + e, err := pe.NewFile(r) + if err != nil { + return nil, err + } + return &peExe{r: r, f: e}, nil + } + if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) { + e, err := macho.NewFile(r) + if err != nil { + return nil, err + } + return &machoExe{f: e}, nil + } + return nil, fmt.Errorf("unrecognized executable format") +} + +type exe interface { + // ReadData reads and returns up to size byte starting at virtual address addr. + ReadData(addr, size uint64) ([]byte, error) + + // DataStart returns the virtual address of the segment or section that + // should contain build information. This is either a specially named section + // or the first writable non-zero data segment. + DataStart() uint64 + + PCLNTab() ([]byte, uint64) // Addition: for constructing symbol table + + SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) // Addition: for inlining purposes +} + +// elfExe is the ELF implementation of the exe interface. +type elfExe struct { + f *elf.File + + symbols map[string]*elf.Symbol // Addition: symbols in the binary + symbolsOnce sync.Once // Addition: for computing symbols + symbolsErr error // Addition: error for computing symbols +} + +func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) { + for _, prog := range x.f.Progs { + if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 { + n := prog.Vaddr + prog.Filesz - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") // Addition: custom error +} + +func (x *elfExe) DataStart() uint64 { + for _, s := range x.f.Sections { + if s.Name == ".go.buildinfo" { + return s.Addr + } + } + for _, p := range x.f.Progs { + if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W { + return p.Vaddr + } + } + return 0 +} + +// peExe is the PE (Windows Portable Executable) implementation of the exe interface. +type peExe struct { + r io.ReaderAt + f *pe.File + + symbols map[string]*pe.Symbol // Addition: symbols in the binary + symbolsOnce sync.Once // Addition: for computing symbols + symbolsErr error // Addition: error for computing symbols +} + +func (x *peExe) imageBase() uint64 { + switch oh := x.f.OptionalHeader.(type) { + case *pe.OptionalHeader32: + return uint64(oh.ImageBase) + case *pe.OptionalHeader64: + return oh.ImageBase + } + return 0 +} + +func (x *peExe) ReadData(addr, size uint64) ([]byte, error) { + addr -= x.imageBase() + for _, sect := range x.f.Sections { + if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) { + n := uint64(sect.VirtualAddress+sect.Size) - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress))) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") // Addition: custom error +} + +func (x *peExe) DataStart() uint64 { + // Assume data is first writable section. + const ( + IMAGE_SCN_CNT_CODE = 0x00000020 + IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 + IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 + IMAGE_SCN_MEM_EXECUTE = 0x20000000 + IMAGE_SCN_MEM_READ = 0x40000000 + IMAGE_SCN_MEM_WRITE = 0x80000000 + IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 + IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 + IMAGE_SCN_ALIGN_32BYTES = 0x600000 + ) + for _, sect := range x.f.Sections { + if sect.VirtualAddress != 0 && sect.Size != 0 && + sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE { + return uint64(sect.VirtualAddress) + x.imageBase() + } + } + return 0 +} + +// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface. +type machoExe struct { + f *macho.File + + symbols map[string]*macho.Symbol // Addition: symbols in the binary + symbolsOnce sync.Once // Addition: for computing symbols + symbolsErr error // Addition: error for computing symbols +} + +func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) { + for _, load := range x.f.Loads { + seg, ok := load.(*macho.Segment) + if !ok { + continue + } + if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 { + if seg.Name == "__PAGEZERO" { + continue + } + n := seg.Addr + seg.Filesz - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := seg.ReadAt(data, int64(addr-seg.Addr)) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") // Addition: custom error +} + +func (x *machoExe) DataStart() uint64 { + // Look for section named "__go_buildinfo". + for _, sec := range x.f.Sections { + if sec.Name == "__go_buildinfo" { + return sec.Addr + } + } + // Try the first non-empty writable segment. + const RW = 3 + for _, load := range x.f.Loads { + seg, ok := load.(*macho.Segment) + if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW { + return seg.Addr + } + } + return 0 +} diff --git a/vendor/golang.org/x/vuln/internal/client/client.go b/vendor/golang.org/x/vuln/internal/client/client.go new file mode 100644 index 000000000..236c9d1b0 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/client/client.go @@ -0,0 +1,347 @@ +// Copyright 2023 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 client provides an interface for accessing vulnerability +// databases, via either HTTP or local filesystem access. +// +// The protocol is described at https://go.dev/security/vuln/database. +package client + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "path/filepath" + "sort" + "strings" + "time" + + "golang.org/x/sync/errgroup" + "golang.org/x/vuln/internal/derrors" + "golang.org/x/vuln/internal/osv" + isem "golang.org/x/vuln/internal/semver" + "golang.org/x/vuln/internal/web" +) + +// A Client for reading vulnerability databases. +type Client struct { + source +} + +type Options struct { + HTTPClient *http.Client +} + +// NewClient returns a client that reads the vulnerability database +// in source (an "http" or "file" prefixed URL). +// +// It supports databases following the API described +// in https://go.dev/security/vuln/database#api. +func NewClient(source string, opts *Options) (_ *Client, err error) { + source = strings.TrimRight(source, "/") + uri, err := url.Parse(source) + if err != nil { + return nil, err + } + switch uri.Scheme { + case "http", "https": + return newHTTPClient(uri, opts) + case "file": + return newLocalClient(uri) + default: + return nil, fmt.Errorf("source %q has unsupported scheme", uri) + } +} + +var errUnknownSchema = errors.New("unrecognized vulndb format; see https://go.dev/security/vuln/database#api for accepted schema") + +func newHTTPClient(uri *url.URL, opts *Options) (*Client, error) { + source := uri.String() + + // v1 returns true if the source likely follows the V1 schema. + v1 := func() bool { + return source == "https://vuln.go.dev" || + endpointExistsHTTP(source, "index/modules.json.gz") + } + + if v1() { + return &Client{source: newHTTPSource(uri.String(), opts)}, nil + } + + return nil, errUnknownSchema +} + +func endpointExistsHTTP(source, endpoint string) bool { + r, err := http.Head(source + "/" + endpoint) + return err == nil && r.StatusCode == http.StatusOK +} + +func newLocalClient(uri *url.URL) (*Client, error) { + dir, err := toDir(uri) + if err != nil { + return nil, err + } + + // Check if the DB likely follows the v1 schema by + // looking for the "index/modules.json" endpoint. + if endpointExistsDir(dir, modulesEndpoint+".json") { + return &Client{source: newLocalSource(dir)}, nil + } + + // If the DB doesn't follow the v1 schema, + // attempt to intepret it as a flat list of OSV files. + // This is currently a "hidden" feature, so don't output the + // specific error if this fails. + src, err := newHybridSource(dir) + if err != nil { + return nil, errUnknownSchema + } + return &Client{source: src}, nil +} + +func toDir(uri *url.URL) (string, error) { + dir, err := web.URLToFilePath(uri) + if err != nil { + return "", err + } + fi, err := os.Stat(dir) + if err != nil { + return "", err + } + if !fi.IsDir() { + return "", fmt.Errorf("%s is not a directory", dir) + } + return dir, nil +} + +func endpointExistsDir(dir, endpoint string) bool { + _, err := os.Stat(filepath.Join(dir, endpoint)) + return err == nil +} + +func NewInMemoryClient(entries []*osv.Entry) (*Client, error) { + s, err := newInMemorySource(entries) + if err != nil { + return nil, err + } + return &Client{source: s}, nil +} + +func (c *Client) LastModifiedTime(ctx context.Context) (_ time.Time, err error) { + derrors.Wrap(&err, "LastModifiedTime()") + + b, err := c.source.get(ctx, dbEndpoint) + if err != nil { + return time.Time{}, err + } + + var dbMeta dbMeta + if err := json.Unmarshal(b, &dbMeta); err != nil { + return time.Time{}, err + } + + return dbMeta.Modified, nil +} + +type ModuleRequest struct { + // The module path to filter on. + // This must be set (if empty, ByModule errors). + Path string + // (Optional) If set, only return vulnerabilities affected + // at this version. + Version string +} + +type ModuleResponse struct { + Path string + Version string + Entries []*osv.Entry +} + +// ByModules returns a list of responses +// containing the OSV entries corresponding to each request. +// +// The order of the requests is preserved, and each request has +// a response even if there are no entries (in which case the Entries +// field is nil). +func (c *Client) ByModules(ctx context.Context, reqs []*ModuleRequest) (_ []*ModuleResponse, err error) { + derrors.Wrap(&err, "ByModules(%v)", reqs) + + metas, err := c.moduleMetas(ctx, reqs) + if err != nil { + return nil, err + } + + resps := make([]*ModuleResponse, len(reqs)) + g, gctx := errgroup.WithContext(ctx) + g.SetLimit(10) + for i, req := range reqs { + i, req := i, req + g.Go(func() error { + entries, err := c.byModule(gctx, req, metas[i]) + if err != nil { + return err + } + resps[i] = &ModuleResponse{ + Path: req.Path, + Version: req.Version, + Entries: entries, + } + return nil + }) + } + if err := g.Wait(); err != nil { + return nil, err + } + + return resps, nil +} + +func (c *Client) moduleMetas(ctx context.Context, reqs []*ModuleRequest) (_ []*moduleMeta, err error) { + b, err := c.source.get(ctx, modulesEndpoint) + if err != nil { + return nil, err + } + + dec, err := newStreamDecoder(b) + if err != nil { + return nil, err + } + + metas := make([]*moduleMeta, len(reqs)) + for dec.More() { + var m moduleMeta + err := dec.Decode(&m) + if err != nil { + return nil, err + } + for i, req := range reqs { + if m.Path == req.Path { + metas[i] = &m + } + } + } + + return metas, nil +} + +// byModule returns the OSV entries matching the ModuleRequest, +// or (nil, nil) if there are none. +func (c *Client) byModule(ctx context.Context, req *ModuleRequest, m *moduleMeta) (_ []*osv.Entry, err error) { + // This module isn't in the database. + if m == nil { + return nil, nil + } + + if req.Path == "" { + return nil, fmt.Errorf("module path must be set") + } + + if req.Version != "" && !isem.Valid(req.Version) { + return nil, fmt.Errorf("version %s is not valid semver", req.Version) + } + + var ids []string + for _, v := range m.Vulns { + if v.Fixed == "" || isem.Less(req.Version, v.Fixed) { + ids = append(ids, v.ID) + } + } + + if len(ids) == 0 { + return nil, nil + } + + entries, err := c.byIDs(ctx, ids) + if err != nil { + return nil, err + } + + // Filter by version. + if req.Version != "" { + affected := func(e *osv.Entry) bool { + for _, a := range e.Affected { + if a.Module.Path == req.Path && isem.Affects(a.Ranges, req.Version) { + return true + } + } + return false + } + + var filtered []*osv.Entry + for _, entry := range entries { + if affected(entry) { + filtered = append(filtered, entry) + } + } + if len(filtered) == 0 { + return nil, nil + } + } + + sort.SliceStable(entries, func(i, j int) bool { + return entries[i].ID < entries[j].ID + }) + + return entries, nil +} + +func (c *Client) byIDs(ctx context.Context, ids []string) (_ []*osv.Entry, err error) { + entries := make([]*osv.Entry, len(ids)) + g, gctx := errgroup.WithContext(ctx) + g.SetLimit(10) + for i, id := range ids { + i, id := i, id + g.Go(func() error { + e, err := c.byID(gctx, id) + if err != nil { + return err + } + entries[i] = e + return nil + }) + } + if err := g.Wait(); err != nil { + return nil, err + } + + return entries, nil +} + +// byID returns the OSV entry with the given ID, +// or an error if it does not exist / cannot be unmarshaled. +func (c *Client) byID(ctx context.Context, id string) (_ *osv.Entry, err error) { + derrors.Wrap(&err, "byID(%s)", id) + + b, err := c.source.get(ctx, entryEndpoint(id)) + if err != nil { + return nil, err + } + + var entry osv.Entry + if err := json.Unmarshal(b, &entry); err != nil { + return nil, err + } + + return &entry, nil +} + +// newStreamDecoder returns a decoder that can be used +// to read an array of JSON objects. +func newStreamDecoder(b []byte) (*json.Decoder, error) { + dec := json.NewDecoder(bytes.NewBuffer(b)) + + // skip open bracket + _, err := dec.Token() + if err != nil { + return nil, err + } + + return dec, nil +} diff --git a/vendor/golang.org/x/vuln/internal/client/index.go b/vendor/golang.org/x/vuln/internal/client/index.go new file mode 100644 index 000000000..435980c47 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/client/index.go @@ -0,0 +1,120 @@ +// Copyright 2023 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 client + +import ( + "encoding/json" + "fmt" + "io/fs" + "os" + "path/filepath" + + "golang.org/x/vuln/internal/osv" + isem "golang.org/x/vuln/internal/semver" +) + +// indexFromDir returns a raw index created from a directory +// containing OSV entries. +// It skips any non-JSON files but errors if any of the JSON files +// cannot be unmarshaled into OSV, or have a filename other than .json. +func indexFromDir(dir string) (map[string][]byte, error) { + idx := newIndex() + f := os.DirFS(dir) + + if err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + fname := d.Name() + ext := filepath.Ext(fname) + switch { + case err != nil: + return err + case d.IsDir(): + return nil + case ext != ".json": + return nil + } + + b, err := fs.ReadFile(f, d.Name()) + if err != nil { + return err + } + var entry osv.Entry + if err := json.Unmarshal(b, &entry); err != nil { + return err + } + if fname != entry.ID+".json" { + return fmt.Errorf("OSV entries must have filename of the form .json, got %s", fname) + } + + idx.add(&entry) + return nil + }); err != nil { + return nil, err + } + + return idx.raw() +} + +func indexFromEntries(entries []*osv.Entry) (map[string][]byte, error) { + idx := newIndex() + + for _, entry := range entries { + idx.add(entry) + } + + return idx.raw() +} + +type index struct { + db *dbMeta + modules modulesIndex +} + +func newIndex() *index { + return &index{ + db: &dbMeta{}, + modules: make(map[string]*moduleMeta), + } +} + +func (i *index) add(entry *osv.Entry) { + // Add to db index. + if entry.Modified.After(i.db.Modified) { + i.db.Modified = entry.Modified + } + // Add to modules index. + for _, affected := range entry.Affected { + modulePath := affected.Module.Path + if _, ok := i.modules[modulePath]; !ok { + i.modules[modulePath] = &moduleMeta{ + Path: modulePath, + Vulns: []moduleVuln{}, + } + } + module := i.modules[modulePath] + module.Vulns = append(module.Vulns, moduleVuln{ + ID: entry.ID, + Modified: entry.Modified, + Fixed: isem.NonSupersededFix(affected.Ranges), + }) + } +} + +func (i *index) raw() (map[string][]byte, error) { + data := make(map[string][]byte) + + b, err := json.Marshal(i.db) + if err != nil { + return nil, err + } + data[dbEndpoint] = b + + b, err = json.Marshal(i.modules) + if err != nil { + return nil, err + } + data[modulesEndpoint] = b + + return data, nil +} diff --git a/vendor/golang.org/x/vuln/internal/client/schema.go b/vendor/golang.org/x/vuln/internal/client/schema.go new file mode 100644 index 000000000..0b8423733 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/client/schema.go @@ -0,0 +1,77 @@ +// Copyright 2023 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 client + +import ( + "encoding/json" + "path" + "sort" + "time" +) + +const ( + idDir = "ID" + indexDir = "index" +) + +var ( + dbEndpoint = path.Join(indexDir, "db") + modulesEndpoint = path.Join(indexDir, "modules") +) + +func entryEndpoint(id string) string { + return path.Join(idDir, id) +} + +// dbMeta contains metadata about the database itself. +type dbMeta struct { + // Modified is the time the database was last modified, calculated + // as the most recent time any single OSV entry was modified. + Modified time.Time `json:"modified"` +} + +// moduleMeta contains metadata about a Go module that has one +// or more vulnerabilities in the database. +// +// Found in the "index/modules" endpoint of the vulnerability database. +type moduleMeta struct { + // Path is the module path. + Path string `json:"path"` + // Vulns is a list of vulnerabilities that affect this module. + Vulns []moduleVuln `json:"vulns"` +} + +// moduleVuln contains metadata about a vulnerability that affects +// a certain module. +type moduleVuln struct { + // ID is a unique identifier for the vulnerability. + // The Go vulnerability database issues IDs of the form + // GO--. + ID string `json:"id"` + // Modified is the time the vuln was last modified. + Modified time.Time `json:"modified"` + // Fixed is the latest version that introduces a fix for the + // vulnerability, in SemVer 2.0.0 format, with no leading "v" prefix. + Fixed string `json:"fixed,omitempty"` +} + +// modulesIndex represents an in-memory modules index. +type modulesIndex map[string]*moduleMeta + +func (m modulesIndex) MarshalJSON() ([]byte, error) { + modules := make([]*moduleMeta, 0, len(m)) + for _, module := range m { + modules = append(modules, module) + } + sort.SliceStable(modules, func(i, j int) bool { + return modules[i].Path < modules[j].Path + }) + for _, module := range modules { + sort.SliceStable(module.Vulns, func(i, j int) bool { + return module.Vulns[i].ID < module.Vulns[j].ID + }) + } + return json.Marshal(modules) +} diff --git a/vendor/golang.org/x/vuln/internal/client/source.go b/vendor/golang.org/x/vuln/internal/client/source.go new file mode 100644 index 000000000..2e848c320 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/client/source.go @@ -0,0 +1,150 @@ +// Copyright 2023 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 client + +import ( + "compress/gzip" + "context" + "encoding/json" + "fmt" + "io" + "io/fs" + "net/http" + "os" + "path/filepath" + + "golang.org/x/vuln/internal/derrors" + "golang.org/x/vuln/internal/osv" +) + +type source interface { + // get returns the raw, uncompressed bytes at the + // requested endpoint, which should be bare with no file extensions + // (e.g., "index/modules" instead of "index/modules.json.gz"). + // It errors if the endpoint cannot be reached or does not exist + // in the expected form. + get(ctx context.Context, endpoint string) ([]byte, error) +} + +func newHTTPSource(url string, opts *Options) *httpSource { + c := http.DefaultClient + if opts != nil && opts.HTTPClient != nil { + c = opts.HTTPClient + } + return &httpSource{url: url, c: c} +} + +// httpSource reads a vulnerability database from an http(s) source. +type httpSource struct { + url string + c *http.Client +} + +func (hs *httpSource) get(ctx context.Context, endpoint string) (_ []byte, err error) { + derrors.Wrap(&err, "get(%s)", endpoint) + + method := http.MethodGet + reqURL := fmt.Sprintf("%s/%s", hs.url, endpoint+".json.gz") + req, err := http.NewRequestWithContext(ctx, method, reqURL, nil) + if err != nil { + return nil, err + } + resp, err := hs.c.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("HTTP %s %s returned unexpected status: %s", method, reqURL, resp.Status) + } + + // Uncompress the result. + r, err := gzip.NewReader(resp.Body) + if err != nil { + return nil, err + } + defer r.Close() + + return io.ReadAll(r) +} + +func newLocalSource(dir string) *localSource { + return &localSource{fs: os.DirFS(dir)} +} + +// localSource reads a vulnerability database from a local file system. +type localSource struct { + fs fs.FS +} + +func (ls *localSource) get(ctx context.Context, endpoint string) (_ []byte, err error) { + derrors.Wrap(&err, "get(%s)", endpoint) + + return fs.ReadFile(ls.fs, endpoint+".json") +} + +func newHybridSource(dir string) (*hybridSource, error) { + index, err := indexFromDir(dir) + if err != nil { + return nil, err + } + + return &hybridSource{ + index: &inMemorySource{data: index}, + osv: &localSource{fs: os.DirFS(dir)}, + }, nil +} + +// hybridSource reads OSV entries from a local file system, but reads +// indexes from an in-memory map. +type hybridSource struct { + index *inMemorySource + osv *localSource +} + +func (hs *hybridSource) get(ctx context.Context, endpoint string) (_ []byte, err error) { + derrors.Wrap(&err, "get(%s)", endpoint) + + dir, file := filepath.Split(endpoint) + + if filepath.Dir(dir) == indexDir { + return hs.index.get(ctx, endpoint) + } + + return hs.osv.get(ctx, file) +} + +// newInMemorySource creates a new in-memory source from OSV entries. +// Adapted from x/vulndb/internal/database.go. +func newInMemorySource(entries []*osv.Entry) (*inMemorySource, error) { + data, err := indexFromEntries(entries) + if err != nil { + return nil, err + } + + for _, entry := range entries { + b, err := json.Marshal(entry) + if err != nil { + return nil, err + } + data[entryEndpoint(entry.ID)] = b + } + + return &inMemorySource{data: data}, nil +} + +// inMemorySource reads databases from an in-memory map. +// Currently intended for use only in unit tests. +type inMemorySource struct { + data map[string][]byte +} + +func (db *inMemorySource) get(ctx context.Context, endpoint string) ([]byte, error) { + b, ok := db.data[endpoint] + if !ok { + return nil, fmt.Errorf("no data found at endpoint %q", endpoint) + } + return b, nil +} diff --git a/vendor/golang.org/x/vuln/internal/gosym/README.md b/vendor/golang.org/x/vuln/internal/gosym/README.md new file mode 100644 index 000000000..dacb83ff2 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/gosym/README.md @@ -0,0 +1,11 @@ +This code is a copied and slightly modified version of go/src/debug/gosym. + +The original code contains logic for accessing symbol tables and line numbers +in Go binaries. The only reason why this is copied is to support inlining. + +Code added by vulncheck is located in files with "additions_" prefix and it +contains logic for accessing inlining information. + +Within the originally named files, deleted or added logic is annotated with +a comment starting with "Addition:". The modified logic allows the inlining +code in "additions_*" files to access the necessary information. diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/additions.go b/vendor/golang.org/x/vuln/internal/gosym/additions.go similarity index 68% rename from vendor/golang.org/x/vuln/vulncheck/internal/gosym/additions.go rename to vendor/golang.org/x/vuln/internal/gosym/additions.go index 2cfec6e75..4c41f5582 100644 --- a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/additions.go +++ b/vendor/golang.org/x/vuln/internal/gosym/additions.go @@ -7,19 +7,40 @@ package gosym import ( "encoding/binary" "io" + "strings" + + sv "golang.org/x/mod/semver" + "golang.org/x/vuln/internal/semver" +) + +const ( + funcSymNameGo119Lower string = "go.func.*" + funcSymNameGo120 string = "go:func.*" ) -// Additions to the original package. +// FuncSymName returns symbol name for Go functions used in binaries +// based on Go version. Supported Go versions are 1.18 and greater. +// If the go version is unreadable it assumes that it is a newer version +// and returns the symbol name for go version 1.20 or greater. +func FuncSymName(goVersion string) string { + // Support devel goX.Y... + v := strings.TrimPrefix(goVersion, "devel ") + v = semver.GoTagToSemver(v) + mm := sv.MajorMinor(v) + if sv.Compare(mm, "v1.20") >= 0 || mm == "" { + return funcSymNameGo120 + } else if sv.Compare(mm, "v1.18") >= 0 { + return funcSymNameGo119Lower + } + return "" +} -// from cmd/internal/objabi/funcdata.go +// Additions to the original package from cmd/internal/objabi/funcdata.go const ( pcdata_InlTreeIndex = 2 funcdata_InlTree = 3 ) -func (f funcData) npcdata() uint32 { return f.field(7) } -func (f funcData) nfuncdata() uint32 { return uint32(f.data[f.fieldOffset(9)+3]) } - // InlineTree returns the inline tree for Func f as a sequence of InlinedCalls. // goFuncValue is the value of the gosym.FuncSymName symbol. // baseAddr is the address of the memory region (ELF Prog) containing goFuncValue. @@ -88,23 +109,29 @@ type rawInlinedCall112 struct { // rawInlinedCall120 is the encoding of entries in the FUNCDATA_InlTree table // from Go 1.20. It is equivalent to runtime.inlinedCall. type rawInlinedCall120 struct { - FuncID uint8 // type of the called function - _ [3]byte - NameOff int32 // offset into pclntab for name of called function - ParentPC int32 // position of an instruction whose source position is the call site (offset from entry) + FuncID uint8 // type of the called function + _ [3]byte + NameOff int32 // offset into pclntab for name of called function + ParentPC int32 // position of an instruction whose source position is the call site (offset from entry) + StartLine int32 // line number of start of function (func keyword/TEXT directive) +} + +func (f funcData) npcdata() uint32 { return f.field(7) } +func (f funcData) nfuncdata(numFuncFields uint32) uint32 { + return uint32(f.data[f.fieldOffset(numFuncFields-1)+3]) } -func (f funcData) funcdataOffset(i uint8) uint32 { - if uint32(i) >= f.nfuncdata() { +func (f funcData) funcdataOffset(i uint8, numFuncFields uint32) uint32 { + if uint32(i) >= f.nfuncdata(numFuncFields) { return ^uint32(0) } var off uint32 if f.t.version >= ver118 { - off = f.fieldOffset(10) + // skip fixed part of _func + off = f.fieldOffset(numFuncFields) + // skip fixed part of _func f.npcdata()*4 + // skip pcdata uint32(i)*4 // index of i'th FUNCDATA } else { - off = f.fieldOffset(10) + // skip fixed part of _func + off = f.fieldOffset(numFuncFields) + // skip fixed part of _func f.npcdata()*4 off += uint32(i) * f.t.ptrsize } @@ -121,11 +148,11 @@ func (f funcData) fieldOffset(n uint32) uint32 { return sz0 + (n-1)*4 // subsequent fields are 4 bytes each } -func (f funcData) pcdataOffset(i uint8) uint32 { +func (f funcData) pcdataOffset(i uint8, numFuncFields uint32) uint32 { if uint32(i) >= f.npcdata() { return ^uint32(0) } - off := f.fieldOffset(10) + // skip fixed part of _func + off := f.fieldOffset(numFuncFields) + // skip fixed part of _func uint32(i)*4 // index of i'th PCDATA return f.t.binary.Uint32(f.data[off:]) } @@ -134,11 +161,11 @@ func (f funcData) pcdataOffset(i uint8) uint32 { // pc-value table in info. This is the only way to determine how many // IndexedCalls are in an inline tree, since the data of the tree itself is not // delimited in any way. -func (t *LineTable) maxInlineTreeIndexValue(info funcData) int { +func (t *LineTable) maxInlineTreeIndexValue(info funcData, numFuncFields uint32) int { if info.npcdata() <= pcdata_InlTreeIndex { return -1 } - off := info.pcdataOffset(pcdata_InlTreeIndex) + off := info.pcdataOffset(pcdata_InlTreeIndex, numFuncFields) p := t.pctab[off:] val := int32(-1) max := int32(-1) diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/pclntab.go b/vendor/golang.org/x/vuln/internal/gosym/pclntab.go similarity index 96% rename from vendor/golang.org/x/vuln/vulncheck/internal/gosym/pclntab.go rename to vendor/golang.org/x/vuln/internal/gosym/pclntab.go index b6dac006e..5fa5e9756 100644 --- a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/pclntab.go +++ b/vendor/golang.org/x/vuln/internal/gosym/pclntab.go @@ -204,7 +204,7 @@ func (t *LineTable) parsePclnTab() { if !disableRecover { defer func() { // If we panic parsing, assume it's a Go 1.1 pclntab. - recover() + _ = recover() }() } @@ -297,7 +297,7 @@ func (t *LineTable) go12Funcs() []Func { // Assume it is malformed and return nil on error. if !disableRecover { defer func() { - recover() + _ = recover() }() } @@ -311,8 +311,19 @@ func (t *LineTable) go12Funcs() []Func { info := t.funcData(uint32(i)) f.LineTable = t f.FrameSize = int(info.deferreturn()) - f.inlineTreeOffset = info.funcdataOffset(funcdata_InlTree) - f.inlineTreeCount = 1 + t.maxInlineTreeIndexValue(info) + + // Additions: + // numFuncField is the number of (32 bit) fields in _func (src/runtime/runtime2.go) + // Note that the last 4 fields are 32 bits combined. This number is 11 for go1.20, + // 10 for earlier versions down to go1.16, and 9 before that. + var numFuncFields uint32 = 11 + if t.version < ver116 { + numFuncFields = 9 + } else if t.version < ver120 { + numFuncFields = 10 + } + f.inlineTreeOffset = info.funcdataOffset(funcdata_InlTree, numFuncFields) + f.inlineTreeCount = 1 + t.maxInlineTreeIndexValue(info, numFuncFields) syms[i] = Sym{ Value: f.Entry, @@ -472,6 +483,7 @@ func (f funcData) field(n uint32) uint32 { if n == 0 || n > 9 { panic("bad funcdata field") } + // Addition: some code deleted here to support inlining. off := f.fieldOffset(n) data := f.data[off:] return f.t.binary.Uint32(data) @@ -677,7 +689,7 @@ func (t *LineTable) initFileMap() { func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) { if !disableRecover { defer func() { - recover() + _ = recover() }() } diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/symtab.go b/vendor/golang.org/x/vuln/internal/gosym/symtab.go similarity index 99% rename from vendor/golang.org/x/vuln/vulncheck/internal/gosym/symtab.go rename to vendor/golang.org/x/vuln/internal/gosym/symtab.go index 1d51a2523..7f172ffff 100644 --- a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/symtab.go +++ b/vendor/golang.org/x/vuln/internal/gosym/symtab.go @@ -137,6 +137,7 @@ type Func struct { FrameSize int LineTable *LineTable Obj *Obj + // Addition: extra data to support inlining. inlTree } @@ -326,7 +327,7 @@ func walksymtab(data []byte, fn func(sym) error) error { s.gotype = uint64(order.Uint32(p[:4])) p = p[4:] } - fn(s) + _ = fn(s) } return nil } diff --git a/vendor/golang.org/x/vuln/internal/govulncheck/govulncheck.go b/vendor/golang.org/x/vuln/internal/govulncheck/govulncheck.go new file mode 100644 index 000000000..7d4f5c9ed --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/govulncheck/govulncheck.go @@ -0,0 +1,189 @@ +// Copyright 2023 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 govulncheck contains the JSON output structs for govulncheck. +// +// govulncheck supports streaming JSON by emitting a series of Message +// objects as it analyzes user code and discovers vulnerabilities. +// Streaming JSON is useful for displaying progress in real-time for +// large projects where govulncheck execution might take some time. +// +// govulncheck JSON emits configuration used to perform the analysis, +// a user-friendly message about what is being analyzed, and the +// vulnerability findings. Findings for the same vulnerability can +// can be emitted several times. For instance, govulncheck JSON will +// emit a finding when it sees that a vulnerable module is required +// before proceeding to check if the vulnerability is imported or called. +// Please see documentation on Message and related types for precise +// details on the stream encoding. +// +// There are no guarantees on the order of messages. The pattern of emitted +// messages can change in the future. Clients can follow code in handler.go +// for consuming the streaming JSON programmatically. +package govulncheck + +import ( + "time" + + "golang.org/x/vuln/internal/osv" +) + +const ( + // ProtocolVersion is the current protocol version this file implements + ProtocolVersion = "v1.0.0" +) + +// Message is an entry in the output stream. It will always have exactly one +// field filled in. +type Message struct { + Config *Config `json:"config,omitempty"` + Progress *Progress `json:"progress,omitempty"` + OSV *osv.Entry `json:"osv,omitempty"` + Finding *Finding `json:"finding,omitempty"` +} + +// Config must occur as the first message of a stream and informs the client +// about the information used to generate the findings. +// The only required field is the protocol version. +type Config struct { + // ProtocolVersion specifies the version of the JSON protocol. + ProtocolVersion string `json:"protocol_version"` + + // ScannerName is the name of the tool, for example, govulncheck. + // + // We expect this JSON format to be used by other tools that wrap + // govulncheck, which will have a different name. + ScannerName string `json:"scanner_name,omitempty"` + + // ScannerVersion is the version of the tool. + ScannerVersion string `json:"scanner_version,omitempty"` + + // DB is the database used by the tool, for example, + // vuln.go.dev. + DB string `json:"db,omitempty"` + + // LastModified is the last modified time of the data source. + DBLastModified *time.Time `json:"db_last_modified,omitempty"` + + // GoVersion is the version of Go used for analyzing standard library + // vulnerabilities. + GoVersion string `json:"go_version,omitempty"` + + // ScanLevel instructs govulncheck to analyze at a specific level of detail. + // Valid values include module, package and symbol. + ScanLevel ScanLevel `json:"scan_level,omitempty"` +} + +// Progress messages are informational only, intended to allow users to monitor +// the progress of a long running scan. +// A stream must remain fully valid and able to be interpreted with all progress +// messages removed. +type Progress struct { + // A time stamp for the message. + Timestamp *time.Time `json:"time,omitempty"` + + // Message is the progress message. + Message string `json:"message,omitempty"` +} + +// Finding contains information on a discovered vulnerability. Each vulnerability +// will likely have multiple findings in JSON mode. This is because govulncheck +// emits findings as it does work, and therefore could emit one module level, +// one package level, and potentially multiple symbol level findings depending +// on scan level. +// Multiple symbol level findings can be emitted when multiple symbols of the +// same vuln are called or govulncheck decides to show multiple traces for the +// same symbol. +type Finding struct { + // OSV is the id of the detected vulnerability. + OSV string `json:"osv,omitempty"` + + // FixedVersion is the module version where the vulnerability was + // fixed. This is empty if a fix is not available. + // + // If there are multiple fixed versions in the OSV report, this will + // be the fixed version in the latest range event for the OSV report. + // + // For example, if the range events are + // {introduced: 0, fixed: 1.0.0} and {introduced: 1.1.0}, the fixed version + // will be empty. + // + // For the stdlib, we will show the fixed version closest to the + // Go version that is used. For example, if a fix is available in 1.17.5 and + // 1.18.5, and the GOVERSION is 1.17.3, 1.17.5 will be returned as the + // fixed version. + FixedVersion string `json:"fixed_version,omitempty"` + + // Trace contains an entry for each frame in the trace. + // + // Frames are sorted starting from the imported vulnerable symbol + // until the entry point. The first frame in Frames should match + // Symbol. + // + // In binary mode, trace will contain a single-frame with no position + // information. + // + // For module level source findings, the trace will contain a single-frame + // with no symbol, position, or package information. For package level source + // findings, the trace will contain a single-frame with no symbol or position + // information. + Trace []*Frame `json:"trace,omitempty"` +} + +// Frame represents an entry in a finding trace. +type Frame struct { + // Module is the module path of the module containing this symbol. + // + // Importable packages in the standard library will have the path "stdlib". + Module string `json:"module"` + + // Version is the module version from the build graph. + Version string `json:"version,omitempty"` + + // Package is the import path. + Package string `json:"package,omitempty"` + + // Function is the function name. + Function string `json:"function,omitempty"` + + // Receiver is the receiver type if the called symbol is a method. + // + // The client can create the final symbol name by + // prepending Receiver to FuncName. + Receiver string `json:"receiver,omitempty"` + + // Position describes an arbitrary source position + // including the file, line, and column location. + // A Position is valid if the line number is > 0. + Position *Position `json:"position,omitempty"` +} + +// Position represents arbitrary source position. +type Position struct { + Filename string `json:"filename,omitempty"` // filename, if any + Offset int `json:"offset"` // byte offset, starting at 0 + Line int `json:"line"` // line number, starting at 1 + Column int `json:"column"` // column number, starting at 1 (byte count) +} + +// ScanLevel represents the detail level at which a scan occurred. +// This can be necessary to correctly interpret the findings, for instance if +// a scan is at symbol level and a finding does not have a symbol it means the +// vulnerability was imported but not called. If the scan however was at +// "package" level, that determination cannot be made. +type ScanLevel string + +const ( + ScanLevelModule = "module" + ScanLevelPackage = "package" + ScanLevelSymbol = "symbol" +) + +// WantSymbols can be used to check whether the scan level is one that is able +// to generate symbols called findings. +func (l ScanLevel) WantSymbols() bool { return l == ScanLevelSymbol } + +// WantPackages can be used to check whether the scan level is one that is able +// to generate package +func (l ScanLevel) WantPackages() bool { return l == ScanLevelPackage || l == ScanLevelSymbol } diff --git a/vendor/golang.org/x/vuln/internal/govulncheck/handler.go b/vendor/golang.org/x/vuln/internal/govulncheck/handler.go new file mode 100644 index 000000000..5676ea94e --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/govulncheck/handler.go @@ -0,0 +1,59 @@ +// Copyright 2023 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 govulncheck + +import ( + "encoding/json" + "io" + + "golang.org/x/vuln/internal/osv" +) + +// Handler handles messages to be presented in a vulnerability scan output +// stream. +type Handler interface { + // Config communicates introductory message to the user. + Config(config *Config) error + + // Progress is called to display a progress message. + Progress(progress *Progress) error + + // OSV is invoked for each osv Entry in the stream. + OSV(entry *osv.Entry) error + + // Finding is called for each vulnerability finding in the stream. + Finding(finding *Finding) error +} + +// HandleJSON reads the json from the supplied stream and hands the decoded +// output to the handler. +func HandleJSON(from io.Reader, to Handler) error { + dec := json.NewDecoder(from) + for dec.More() { + msg := Message{} + // decode the next message in the stream + if err := dec.Decode(&msg); err != nil { + return err + } + // dispatch the message + var err error + if msg.Config != nil { + err = to.Config(msg.Config) + } + if msg.Progress != nil { + err = to.Progress(msg.Progress) + } + if msg.OSV != nil { + err = to.OSV(msg.OSV) + } + if msg.Finding != nil { + err = to.Finding(msg.Finding) + } + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/golang.org/x/vuln/internal/govulncheck/jsonhandler.go b/vendor/golang.org/x/vuln/internal/govulncheck/jsonhandler.go new file mode 100644 index 000000000..d1ea78af8 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/govulncheck/jsonhandler.go @@ -0,0 +1,44 @@ +// Copyright 2022 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 govulncheck + +import ( + "encoding/json" + + "io" + + "golang.org/x/vuln/internal/osv" +) + +type jsonHandler struct { + enc *json.Encoder +} + +// NewJSONHandler returns a handler that writes govulncheck output as json. +func NewJSONHandler(w io.Writer) Handler { + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + return &jsonHandler{enc: enc} +} + +// Config writes config block in JSON to the underlying writer. +func (h *jsonHandler) Config(config *Config) error { + return h.enc.Encode(Message{Config: config}) +} + +// Progress writes a progress message in JSON to the underlying writer. +func (h *jsonHandler) Progress(progress *Progress) error { + return h.enc.Encode(Message{Progress: progress}) +} + +// OSV writes an osv entry in JSON to the underlying writer. +func (h *jsonHandler) OSV(entry *osv.Entry) error { + return h.enc.Encode(Message{OSV: entry}) +} + +// Finding writes a finding in JSON to the underlying writer. +func (h *jsonHandler) Finding(finding *Finding) error { + return h.enc.Encode(Message{Finding: finding}) +} diff --git a/vendor/golang.org/x/vuln/internal/internal.go b/vendor/golang.org/x/vuln/internal/internal.go index dcca07be0..64c5e8d5b 100644 --- a/vendor/golang.org/x/vuln/internal/internal.go +++ b/vendor/golang.org/x/vuln/internal/internal.go @@ -8,3 +8,21 @@ package internal // IDDirectory is the name of the directory that contains entries // listed by their IDs. const IDDirectory = "ID" + +// Pseudo-module paths used for parts of the Go system. +// These are technically not valid module paths, so we +// mustn't pass them to module.EscapePath. +// Keep in sync with vulndb/internal/database/generate.go. +const ( + // GoStdModulePath is the internal Go module path string used + // when listing vulnerabilities in standard library. + GoStdModulePath = "stdlib" + + // GoCmdModulePath is the internal Go module path string used + // when listing vulnerabilities in the go command. + GoCmdModulePath = "toolchain" + + // UnknownModulePath is a special module path for when we cannot work out + // the module for a package. + UnknownModulePath = "unknown" +) diff --git a/vendor/golang.org/x/vuln/internal/osv/osv.go b/vendor/golang.org/x/vuln/internal/osv/osv.go new file mode 100644 index 000000000..5b7e89221 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/osv/osv.go @@ -0,0 +1,238 @@ +// Copyright 2023 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 osv implements the Go OSV vulnerability format +// (https://go.dev/security/vuln/database#schema), which is a subset of +// the OSV shared vulnerability format +// (https://ossf.github.io/osv-schema), with database and +// ecosystem-specific meanings and fields. +// +// As this package is intended for use with the Go vulnerability +// database, only the subset of features which are used by that +// database are implemented (for instance, only the SEMVER affected +// range type is implemented). +package osv + +import "time" + +// RangeType specifies the type of version range being recorded and +// defines the interpretation of the RangeEvent object's Introduced +// and Fixed fields. +// +// In this implementation, only the "SEMVER" type is supported. +// +// See https://ossf.github.io/osv-schema/#affectedrangestype-field. +type RangeType string + +// RangeTypeSemver indicates a semantic version as defined by +// SemVer 2.0.0, with no leading "v" prefix. +const RangeTypeSemver RangeType = "SEMVER" + +// Ecosystem identifies the overall library ecosystem. +// In this implementation, only the "Go" ecosystem is supported. +type Ecosystem string + +// GoEcosystem indicates the Go ecosystem. +const GoEcosystem Ecosystem = "Go" + +// Pseudo-module paths used to describe vulnerabilities +// in the Go standard library and toolchain. +const ( + // GoStdModulePath is the pseudo-module path string used + // to describe vulnerabilities in the Go standard library. + GoStdModulePath = "stdlib" + // GoCmdModulePath is the pseudo-module path string used + // to describe vulnerabilities in the go command. + GoCmdModulePath = "toolchain" +) + +// Module identifies the Go module containing the vulnerability. +// Note that this field is called "package" in the OSV specification. +// +// See https://ossf.github.io/osv-schema/#affectedpackage-field. +type Module struct { + // The Go module path. Required. + // For the Go standard library, this is "stdlib". + // For the Go toolchain, this is "toolchain." + Path string `json:"name"` + // The ecosystem containing the module. Required. + // This should always be "Go". + Ecosystem Ecosystem `json:"ecosystem"` +} + +// RangeEvent describes a single module version that either +// introduces or fixes a vulnerability. +// +// Exactly one of Introduced and Fixed must be present. Other range +// event types (e.g, "last_affected" and "limit") are not supported in +// this implementation. +// +// See https://ossf.github.io/osv-schema/#affectedrangesevents-fields. +type RangeEvent struct { + // Introduced is a version that introduces the vulnerability. + // A special value, "0", represents a version that sorts before + // any other version, and should be used to indicate that the + // vulnerability exists from the "beginning of time". + Introduced string `json:"introduced,omitempty"` + // Fixed is a version that fixes the vulnerability. + Fixed string `json:"fixed,omitempty"` +} + +// Range describes the affected versions of the vulnerable module. +// +// See https://ossf.github.io/osv-schema/#affectedranges-field. +type Range struct { + // Type is the version type that should be used to interpret the + // versions in Events. Required. + // In this implementation, only the "SEMVER" type is supported. + Type RangeType `json:"type"` + // Events is a list of versions representing the ranges in which + // the module is vulnerable. Required. + // The events should be sorted, and MUST represent non-overlapping + // ranges. + // There must be at least one RangeEvent containing a value for + // Introduced. + // See https://ossf.github.io/osv-schema/#examples for examples. + Events []RangeEvent `json:"events"` +} + +// ReferenceType is a reference (link) type. +type ReferenceType string + +const ( + // ReferenceTypeAdvisory is a published security advisory for + // the vulnerability. + ReferenceTypeAdvisory = ReferenceType("ADVISORY") + // ReferenceTypeArticle is an article or blog post describing the vulnerability. + ReferenceTypeArticle = ReferenceType("ARTICLE") + // ReferenceTypeReport is a report, typically on a bug or issue tracker, of + // the vulnerability. + ReferenceTypeReport = ReferenceType("REPORT") + // ReferenceTypeFix is a source code browser link to the fix (e.g., a GitHub commit). + ReferenceTypeFix = ReferenceType("FIX") + // ReferenceTypePackage is a home web page for the package. + ReferenceTypePackage = ReferenceType("PACKAGE") + // ReferenceTypeEvidence is a demonstration of the validity of a vulnerability claim. + ReferenceTypeEvidence = ReferenceType("EVIDENCE") + // ReferenceTypeWeb is a web page of some unspecified kind. + ReferenceTypeWeb = ReferenceType("WEB") +) + +// Reference is a reference URL containing additional information, +// advisories, issue tracker entries, etc., about the vulnerability. +// +// See https://ossf.github.io/osv-schema/#references-field. +type Reference struct { + // The type of reference. Required. + Type ReferenceType `json:"type"` + // The fully-qualified URL of the reference. Required. + URL string `json:"url"` +} + +// Affected gives details about a module affected by the vulnerability. +// +// See https://ossf.github.io/osv-schema/#affected-fields. +type Affected struct { + // The affected Go module. Required. + // Note that this field is called "package" in the OSV specification. + Module Module `json:"package"` + // The module version ranges affected by the vulnerability. + Ranges []Range `json:"ranges,omitempty"` + // Details on the affected packages and symbols within the module. + EcosystemSpecific EcosystemSpecific `json:"ecosystem_specific"` +} + +// Package contains additional information about an affected package. +// This is an ecosystem-specific field for the Go ecosystem. +type Package struct { + // Path is the package import path. Required. + Path string `json:"path,omitempty"` + // GOOS is the execution operating system where the symbols appear, if + // known. + GOOS []string `json:"goos,omitempty"` + // GOARCH specifies the execution architecture where the symbols appear, if + // known. + GOARCH []string `json:"goarch,omitempty"` + // Symbols is a list of function and method names affected by + // this vulnerability. Methods are listed as .. + // + // If included, only programs which use these symbols will be marked as + // vulnerable by `govulncheck`. If omitted, any program which imports this + // package will be marked vulnerable. + Symbols []string `json:"symbols,omitempty"` +} + +// EcosystemSpecific contains additional information about the vulnerable +// module for the Go ecosystem. +// +// See https://go.dev/security/vuln/database#schema. +type EcosystemSpecific struct { + // Packages is the list of affected packages within the module. + Packages []Package `json:"imports,omitempty"` +} + +// Entry represents a vulnerability in the Go OSV format, documented +// in https://go.dev/security/vuln/database#schema. +// It is a subset of the OSV schema (https://ossf.github.io/osv-schema). +// Only fields that are published in the Go Vulnerability Database +// are supported. +type Entry struct { + // SchemaVersion is the OSV schema version used to encode this + // vulnerability. + SchemaVersion string `json:"schema_version,omitempty"` + // ID is a unique identifier for the vulnerability. Required. + // The Go vulnerability database issues IDs of the form + // GO--. + ID string `json:"id"` + // Modified is the time the entry was last modified. Required. + Modified time.Time `json:"modified,omitempty"` + // Published is the time the entry should be considered to have + // been published. + Published time.Time `json:"published,omitempty"` + // Withdrawn is the time the entry should be considered to have + // been withdrawn. If the field is missing, then the entry has + // not been withdrawn. + Withdrawn *time.Time `json:"withdrawn,omitempty"` + // Aliases is a list of IDs for the same vulnerability in other + // databases. + Aliases []string `json:"aliases,omitempty"` + // Summary gives a one-line, English textual summary of the vulnerability. + // It is recommended that this field be kept short, on the order of no more + // than 120 characters. + Summary string `json:"summary,omitempty"` + // Details contains additional English textual details about the vulnerability. + Details string `json:"details"` + // Affected contains information on the modules and versions + // affected by the vulnerability. + Affected []Affected `json:"affected"` + // References contains links to more information about the + // vulnerability. + References []Reference `json:"references,omitempty"` + // Credits contains credits to entities that helped find or fix the + // vulnerability. + Credits []Credit `json:"credits,omitempty"` + // DatabaseSpecific contains additional information about the + // vulnerability, specific to the Go vulnerability database. + DatabaseSpecific *DatabaseSpecific `json:"database_specific,omitempty"` +} + +// Credit represents a credit for the discovery, confirmation, patch, or +// other event in the life cycle of a vulnerability. +// +// See https://ossf.github.io/osv-schema/#credits-fields. +type Credit struct { + // Name is the name, label, or other identifier of the individual or + // entity being credited. Required. + Name string `json:"name"` +} + +// DatabaseSpecific contains additional information about the +// vulnerability, specific to the Go vulnerability database. +// +// See https://go.dev/security/vuln/database#schema. +type DatabaseSpecific struct { + // The URL of the Go advisory for this vulnerability, of the form + // "https://pkg.go.dev/GO-YYYY-XXXX". + URL string `json:"url,omitempty"` +} diff --git a/vendor/golang.org/x/vuln/internal/scan/binary.go b/vendor/golang.org/x/vuln/internal/scan/binary.go new file mode 100644 index 000000000..d404dc976 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/binary.go @@ -0,0 +1,103 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.18 +// +build go1.18 + +package scan + +import ( + "context" + "encoding/json" + "errors" + "io" + "os" + "runtime/debug" + + "golang.org/x/vuln/internal/buildinfo" + "golang.org/x/vuln/internal/client" + "golang.org/x/vuln/internal/derrors" + "golang.org/x/vuln/internal/govulncheck" + "golang.org/x/vuln/internal/vulncheck" +) + +// runBinary detects presence of vulnerable symbols in an executable or its minimal blob representation. +func runBinary(ctx context.Context, handler govulncheck.Handler, cfg *config, client *client.Client) (err error) { + defer derrors.Wrap(&err, "govulncheck") + + bin, err := createBin(cfg.patterns[0]) + if err != nil { + return err + } + + p := &govulncheck.Progress{Message: binaryProgressMessage} + if err := handler.Progress(p); err != nil { + return err + } + return vulncheck.Binary(ctx, handler, bin, &cfg.Config, client) +} + +func createBin(path string) (*vulncheck.Bin, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + // First check if the path points to a Go binary. Otherwise, blob + // parsing might json decode a Go binary which takes time. + // + // TODO(#64716): use fingerprinting to make this precise, clean, and fast. + mods, packageSymbols, bi, err := buildinfo.ExtractPackagesAndSymbols(f) + if err == nil { + return &vulncheck.Bin{ + Modules: mods, + PkgSymbols: packageSymbols, + GoVersion: bi.GoVersion, + GOOS: findSetting("GOOS", bi), + GOARCH: findSetting("GOARCH", bi), + }, nil + } + + // Otherwise, see if the path points to a valid blob. + bin := parseBlob(f) + if bin != nil { + return bin, nil + } + + return nil, errors.New("unrecognized binary format") +} + +// parseBlob extracts vulncheck.Bin from a valid blob. If it +// cannot recognize a valid blob, returns nil. +func parseBlob(from io.Reader) *vulncheck.Bin { + dec := json.NewDecoder(from) + + var h header + if err := dec.Decode(&h); err != nil { + return nil // no header + } else if h.Name != extractModeID || h.Version != extractModeVersion { + return nil // invalid header + } + + var b vulncheck.Bin + if err := dec.Decode(&b); err != nil { + return nil // no body + } + if dec.More() { + return nil // we want just header and body, nothing else + } + return &b +} + +// findSetting returns value of setting from bi if present. +// Otherwise, returns "". +func findSetting(setting string, bi *debug.BuildInfo) string { + for _, s := range bi.Settings { + if s.Key == setting { + return s.Value + } + } + return "" +} diff --git a/vendor/golang.org/x/vuln/internal/scan/color.go b/vendor/golang.org/x/vuln/internal/scan/color.go new file mode 100644 index 000000000..7ef0fca20 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/color.go @@ -0,0 +1,97 @@ +// Copyright 2022 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 scan + +const ( + // These are all the constants for the terminal escape strings + + colorEscape = "\033[" + colorEnd = "m" + + colorReset = colorEscape + "0" + colorEnd + colorBold = colorEscape + "1" + colorEnd + colorFaint = colorEscape + "2" + colorEnd + colorUnderline = colorEscape + "4" + colorEnd + colorBlink = colorEscape + "5" + colorEnd + + fgBlack = colorEscape + "30" + colorEnd + fgRed = colorEscape + "31" + colorEnd + fgGreen = colorEscape + "32" + colorEnd + fgYellow = colorEscape + "33" + colorEnd + fgBlue = colorEscape + "34" + colorEnd + fgMagenta = colorEscape + "35" + colorEnd + fgCyan = colorEscape + "36" + colorEnd + fgWhite = colorEscape + "37" + colorEnd + + bgBlack = colorEscape + "40" + colorEnd + bgRed = colorEscape + "41" + colorEnd + bgGreen = colorEscape + "42" + colorEnd + bgYellow = colorEscape + "43" + colorEnd + bgBlue = colorEscape + "44" + colorEnd + bgMagenta = colorEscape + "45" + colorEnd + bgCyan = colorEscape + "46" + colorEnd + bgWhite = colorEscape + "47" + colorEnd + + fgBlackHi = colorEscape + "90" + colorEnd + fgRedHi = colorEscape + "91" + colorEnd + fgGreenHi = colorEscape + "92" + colorEnd + fgYellowHi = colorEscape + "93" + colorEnd + fgBlueHi = colorEscape + "94" + colorEnd + fgMagentaHi = colorEscape + "95" + colorEnd + fgCyanHi = colorEscape + "96" + colorEnd + fgWhiteHi = colorEscape + "97" + colorEnd + + bgBlackHi = colorEscape + "100" + colorEnd + bgRedHi = colorEscape + "101" + colorEnd + bgGreenHi = colorEscape + "102" + colorEnd + bgYellowHi = colorEscape + "103" + colorEnd + bgBlueHi = colorEscape + "104" + colorEnd + bgMagentaHi = colorEscape + "105" + colorEnd + bgCyanHi = colorEscape + "106" + colorEnd + bgWhiteHi = colorEscape + "107" + colorEnd +) + +const ( + _ = colorReset + _ = colorBold + _ = colorFaint + _ = colorUnderline + _ = colorBlink + + _ = fgBlack + _ = fgRed + _ = fgGreen + _ = fgYellow + _ = fgBlue + _ = fgMagenta + _ = fgCyan + _ = fgWhite + + _ = fgBlackHi + _ = fgRedHi + _ = fgGreenHi + _ = fgYellowHi + _ = fgBlueHi + _ = fgMagentaHi + _ = fgCyanHi + _ = fgWhiteHi + + _ = bgBlack + _ = bgRed + _ = bgGreen + _ = bgYellow + _ = bgBlue + _ = bgMagenta + _ = bgCyan + _ = bgWhite + + _ = bgBlackHi + _ = bgRedHi + _ = bgGreenHi + _ = bgYellowHi + _ = bgBlueHi + _ = bgMagentaHi + _ = bgCyanHi + _ = bgWhiteHi +) diff --git a/vendor/golang.org/x/vuln/internal/scan/errors.go b/vendor/golang.org/x/vuln/internal/scan/errors.go new file mode 100644 index 000000000..920edd4c4 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/errors.go @@ -0,0 +1,67 @@ +// Copyright 2022 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 scan + +import ( + "errors" + "strings" +) + +//lint:file-ignore ST1005 Ignore staticcheck message about error formatting +var ( + // ErrVulnerabilitiesFound indicates that vulnerabilities were detected + // when running govulncheck. This returns exit status 3 when running + // without the -json flag. + errVulnerabilitiesFound = &exitCodeError{message: "vulnerabilities found", code: 3} + + // errHelp indicates that usage help was requested. + errHelp = &exitCodeError{message: "help requested", code: 0} + + // errUsage indicates that there was a usage error on the command line. + // + // In this case, we assume that the user does not know how to run + // govulncheck, and print the usage message with exit status 2. + errUsage = &exitCodeError{message: "invalid usage", code: 2} + + // errGoVersionMismatch is used to indicate that there is a mismatch between + // the Go version used to build govulncheck and the one currently on PATH. + errGoVersionMismatch = errors.New(`Loading packages failed, possibly due to a mismatch between the Go version +used to build govulncheck and the Go version on PATH. Consider rebuilding +govulncheck with the current Go version.`) + + // errNoGoMod indicates that a go.mod file was not found in this module. + errNoGoMod = errors.New(`no go.mod file + +govulncheck only works with Go modules. Try navigating to your module directory. +Otherwise, run go mod init to make your project a module. + +See https://go.dev/doc/modules/managing-dependencies for more information.`) + + // errNoBinaryFlag indicates that govulncheck was run on a file, without + // the -mode=binary flag. + errNoBinaryFlag = errors.New(`By default, govulncheck runs source analysis on Go modules. + +Did you mean to run govulncheck with -mode=binary? + +For details, run govulncheck -h.`) +) + +type exitCodeError struct { + message string + code int +} + +func (e *exitCodeError) Error() string { return e.message } +func (e *exitCodeError) ExitCode() int { return e.code } + +// isGoVersionMismatchError checks if err is due to mismatch between +// the Go version used to build govulncheck and the one currently +// on PATH. +func isGoVersionMismatchError(err error) bool { + msg := err.Error() + // See golang.org/x/tools/go/packages/packages.go. + return strings.Contains(msg, "This application uses version go") && + strings.Contains(msg, "It may fail to process source files") +} diff --git a/vendor/golang.org/x/vuln/internal/scan/extract.go b/vendor/golang.org/x/vuln/internal/scan/extract.go new file mode 100644 index 000000000..30ee09851 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/extract.go @@ -0,0 +1,63 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.18 +// +build go1.18 + +package scan + +import ( + "encoding/json" + "fmt" + "io" + "sort" + + "golang.org/x/vuln/internal/derrors" + "golang.org/x/vuln/internal/vulncheck" +) + +const ( + // extractModeID is the unique name of the extract mode protocol + extractModeID = "govulncheck-extract" + extractModeVersion = "0.1.0" +) + +// header information for the blob output. +type header struct { + Name string `json:"name"` + Version string `json:"version"` +} + +// runExtract dumps the extracted abstraction of binary at cfg.patterns to out. +// It prints out exactly two blob messages, one with the header and one with +// the vulncheck.Bin as the body. +func runExtract(cfg *config, out io.Writer) (err error) { + defer derrors.Wrap(&err, "govulncheck") + + bin, err := createBin(cfg.patterns[0]) + if err != nil { + return err + } + sortBin(bin) // sort for easier testing and validation + header := header{ + Name: extractModeID, + Version: extractModeVersion, + } + + enc := json.NewEncoder(out) + + if err := enc.Encode(header); err != nil { + return fmt.Errorf("marshaling blob header: %v", err) + } + if err := enc.Encode(bin); err != nil { + return fmt.Errorf("marshaling blob body: %v", err) + } + return nil +} + +func sortBin(bin *vulncheck.Bin) { + sort.SliceStable(bin.PkgSymbols, func(i, j int) bool { + return bin.PkgSymbols[i].Pkg+"."+bin.PkgSymbols[i].Name < bin.PkgSymbols[j].Pkg+"."+bin.PkgSymbols[j].Name + }) +} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/filepath.go b/vendor/golang.org/x/vuln/internal/scan/filepath.go similarity index 97% rename from vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/filepath.go rename to vendor/golang.org/x/vuln/internal/scan/filepath.go index 7f447fd48..afd1bb468 100644 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/internal/govulncheck/filepath.go +++ b/vendor/golang.org/x/vuln/internal/scan/filepath.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package govulncheck +package scan import ( "path/filepath" diff --git a/vendor/golang.org/x/vuln/internal/scan/flags.go b/vendor/golang.org/x/vuln/internal/scan/flags.go new file mode 100644 index 000000000..3d361d5c3 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/flags.go @@ -0,0 +1,197 @@ +// Copyright 2022 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 scan + +import ( + "flag" + "fmt" + "io" + "os" + "strings" + + "golang.org/x/tools/go/buildutil" + "golang.org/x/vuln/internal/govulncheck" +) + +type config struct { + govulncheck.Config + patterns []string + mode string + db string + json bool + dir string + tags []string + test bool + show []string + env []string +} + +const ( + modeBinary = "binary" + modeSource = "source" + modeConvert = "convert" // only intended for use by gopls + modeQuery = "query" // only intended for use by gopls + modeExtract = "extract" // currently, only binary extraction is supported +) + +func parseFlags(cfg *config, stderr io.Writer, args []string) error { + var tagsFlag buildutil.TagsFlag + var showFlag showFlag + var version bool + flags := flag.NewFlagSet("", flag.ContinueOnError) + flags.SetOutput(stderr) + flags.BoolVar(&cfg.json, "json", false, "output JSON") + flags.BoolVar(&cfg.test, "test", false, "analyze test files (only valid for source mode, default false)") + flags.StringVar(&cfg.dir, "C", "", "change to `dir` before running govulncheck") + flags.StringVar(&cfg.db, "db", "https://vuln.go.dev", "vulnerability database `url`") + flags.StringVar(&cfg.mode, "mode", modeSource, "supports source or binary") + flags.Var(&tagsFlag, "tags", "comma-separated `list` of build tags") + flags.Var(&showFlag, "show", "enable display of additional information specified by the comma separated `list`\nThe supported values are 'traces','color', 'version', and 'verbose'") + flags.BoolVar(&version, "version", false, "print the version information") + scanLevel := flags.String("scan", "symbol", "set the scanning level desired, one of module, package or symbol") + flags.Usage = func() { + fmt.Fprint(flags.Output(), `Govulncheck reports known vulnerabilities in dependencies. + +Usage: + + govulncheck [flags] [patterns] + govulncheck -mode=binary [flags] [binary] + +`) + flags.PrintDefaults() + fmt.Fprintf(flags.Output(), "\n%s\n", detailsMessage) + } + if err := flags.Parse(args); err != nil { + if err == flag.ErrHelp { + return errHelp + } + return err + } + cfg.patterns = flags.Args() + cfg.tags = tagsFlag + cfg.show = showFlag + if version { + cfg.show = append(cfg.show, "version") + } + cfg.ScanLevel = govulncheck.ScanLevel(*scanLevel) + if err := validateConfig(cfg); err != nil { + fmt.Fprintln(flags.Output(), err) + return errUsage + } + return nil +} + +var supportedModes = map[string]bool{ + modeSource: true, + modeBinary: true, + modeConvert: true, + modeQuery: true, + modeExtract: true, +} + +var supportedLevels = map[string]bool{ + govulncheck.ScanLevelModule: true, + govulncheck.ScanLevelPackage: true, + govulncheck.ScanLevelSymbol: true, +} + +func validateConfig(cfg *config) error { + if _, ok := supportedModes[cfg.mode]; !ok { + return fmt.Errorf("%q is not a valid mode", cfg.mode) + } + if _, ok := supportedLevels[string(cfg.ScanLevel)]; !ok { + return fmt.Errorf("%q is not a valid scan level", cfg.ScanLevel) + } + switch cfg.mode { + case modeSource: + if len(cfg.patterns) == 1 && isFile(cfg.patterns[0]) { + return fmt.Errorf("%q is a file.\n\n%v", cfg.patterns[0], errNoBinaryFlag) + } + if cfg.ScanLevel == govulncheck.ScanLevelModule && len(cfg.patterns) != 0 { + return fmt.Errorf("patterns are not accepted for module only scanning") + } + case modeBinary: + if cfg.test { + return fmt.Errorf("the -test flag is not supported in binary mode") + } + if len(cfg.tags) > 0 { + return fmt.Errorf("the -tags flag is not supported in binary mode") + } + if len(cfg.patterns) != 1 { + return fmt.Errorf("only 1 binary can be analyzed at a time") + } + if !isFile(cfg.patterns[0]) { + return fmt.Errorf("%q is not a file", cfg.patterns[0]) + } + case modeExtract: + if cfg.test { + return fmt.Errorf("the -test flag is not supported in extract mode") + } + if len(cfg.tags) > 0 { + return fmt.Errorf("the -tags flag is not supported in extract mode") + } + if len(cfg.patterns) != 1 { + return fmt.Errorf("only 1 binary can be extracted at a time") + } + if cfg.json { + return fmt.Errorf("the -json flag must be off in extract mode") + } + if !isFile(cfg.patterns[0]) { + return fmt.Errorf("%q is not a file (source extraction is not supported)", cfg.patterns[0]) + } + case modeConvert: + if len(cfg.patterns) != 0 { + return fmt.Errorf("patterns are not accepted in convert mode") + } + if cfg.dir != "" { + return fmt.Errorf("the -C flag is not supported in convert mode") + } + if cfg.test { + return fmt.Errorf("the -test flag is not supported in convert mode") + } + if len(cfg.tags) > 0 { + return fmt.Errorf("the -tags flag is not supported in convert mode") + } + case modeQuery: + if cfg.test { + return fmt.Errorf("the -test flag is not supported in query mode") + } + if len(cfg.tags) > 0 { + return fmt.Errorf("the -tags flag is not supported in query mode") + } + if !cfg.json { + return fmt.Errorf("the -json flag must be set in query mode") + } + for _, pattern := range cfg.patterns { + // Parse the input here so that we can catch errors before + // outputting the Config. + if _, _, err := parseModuleQuery(pattern); err != nil { + return err + } + } + } + if cfg.json && len(cfg.show) > 0 { + return fmt.Errorf("the -show flag is not supported for JSON output") + } + return nil +} + +func isFile(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return !s.IsDir() +} + +type showFlag []string + +func (v *showFlag) Set(s string) error { + *v = append(*v, strings.Split(s, ",")...) + return nil +} + +func (f *showFlag) Get() interface{} { return *f } +func (f *showFlag) String() string { return "" } diff --git a/vendor/golang.org/x/vuln/internal/scan/query.go b/vendor/golang.org/x/vuln/internal/scan/query.go new file mode 100644 index 000000000..7b472180a --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/query.go @@ -0,0 +1,74 @@ +// Copyright 2023 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 scan + +import ( + "context" + "fmt" + "regexp" + + "golang.org/x/vuln/internal/client" + "golang.org/x/vuln/internal/govulncheck" + isem "golang.org/x/vuln/internal/semver" +) + +// runQuery reports vulnerabilities that apply to the queries in the config. +func runQuery(ctx context.Context, handler govulncheck.Handler, cfg *config, c *client.Client) error { + reqs := make([]*client.ModuleRequest, len(cfg.patterns)) + for i, query := range cfg.patterns { + mod, ver, err := parseModuleQuery(query) + if err != nil { + return err + } + if err := handler.Progress(queryProgressMessage(mod, ver)); err != nil { + return err + } + reqs[i] = &client.ModuleRequest{ + Path: mod, Version: ver, + } + } + + resps, err := c.ByModules(ctx, reqs) + if err != nil { + return err + } + + ids := make(map[string]bool) + for _, resp := range resps { + for _, entry := range resp.Entries { + if _, ok := ids[entry.ID]; !ok { + err := handler.OSV(entry) + if err != nil { + return err + } + ids[entry.ID] = true + } + } + } + + return nil +} + +func queryProgressMessage(module, version string) *govulncheck.Progress { + return &govulncheck.Progress{ + Message: fmt.Sprintf("Looking up vulnerabilities in %s at %s...", module, version), + } +} + +var modQueryRegex = regexp.MustCompile(`(.+)@(.+)`) + +func parseModuleQuery(pattern string) (_ string, _ string, err error) { + matches := modQueryRegex.FindStringSubmatch(pattern) + // matches should be [module@version, module, version] + if len(matches) != 3 { + return "", "", fmt.Errorf("invalid query %s: must be of the form module@version", pattern) + } + mod, ver := matches[1], matches[2] + if !isem.Valid(ver) { + return "", "", fmt.Errorf("version %s is not valid semver", ver) + } + + return mod, ver, nil +} diff --git a/vendor/golang.org/x/vuln/internal/scan/run.go b/vendor/golang.org/x/vuln/internal/scan/run.go new file mode 100644 index 000000000..a8fdbb10a --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/run.go @@ -0,0 +1,132 @@ +// Copyright 2022 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 scan + +import ( + "context" + "fmt" + "io" + "os/exec" + "path" + "path/filepath" + "runtime/debug" + "strings" + "time" + + "golang.org/x/vuln/internal/client" + "golang.org/x/vuln/internal/govulncheck" +) + +// RunGovulncheck performs main govulncheck functionality and exits the +// program upon success with an appropriate exit status. Otherwise, +// returns an error. +func RunGovulncheck(ctx context.Context, env []string, r io.Reader, stdout io.Writer, stderr io.Writer, args []string) error { + cfg := &config{env: env} + if err := parseFlags(cfg, stderr, args); err != nil { + return err + } + + client, err := client.NewClient(cfg.db, nil) + if err != nil { + return fmt.Errorf("creating client: %w", err) + } + + prepareConfig(ctx, cfg, client) + var handler govulncheck.Handler + switch { + case cfg.json: + handler = govulncheck.NewJSONHandler(stdout) + default: + th := NewTextHandler(stdout) + th.Show(cfg.show) + handler = th + } + + // Write the introductory message to the user. + if err := handler.Config(&cfg.Config); err != nil { + return err + } + + switch cfg.mode { + case modeSource: + dir := filepath.FromSlash(cfg.dir) + err = runSource(ctx, handler, cfg, client, dir) + case modeBinary: + err = runBinary(ctx, handler, cfg, client) + case modeExtract: + return runExtract(cfg, stdout) + case modeQuery: + err = runQuery(ctx, handler, cfg, client) + case modeConvert: + err = govulncheck.HandleJSON(r, handler) + } + if err != nil { + return err + } + return Flush(handler) +} + +func prepareConfig(ctx context.Context, cfg *config, client *client.Client) { + cfg.ProtocolVersion = govulncheck.ProtocolVersion + cfg.DB = cfg.db + if cfg.mode == modeSource && cfg.GoVersion == "" { + const goverPrefix = "GOVERSION=" + for _, env := range cfg.env { + if val := strings.TrimPrefix(env, goverPrefix); val != env { + cfg.GoVersion = val + } + } + if cfg.GoVersion == "" { + if out, err := exec.Command("go", "env", "GOVERSION").Output(); err == nil { + cfg.GoVersion = strings.TrimSpace(string(out)) + } + } + } + if bi, ok := debug.ReadBuildInfo(); ok { + scannerVersion(cfg, bi) + } + if mod, err := client.LastModifiedTime(ctx); err == nil { + cfg.DBLastModified = &mod + } +} + +// scannerVersion reconstructs the current version of +// this binary used from the build info. +func scannerVersion(cfg *config, bi *debug.BuildInfo) { + if bi.Path != "" { + cfg.ScannerName = path.Base(bi.Path) + } + if bi.Main.Version != "" && bi.Main.Version != "(devel)" { + cfg.ScannerVersion = bi.Main.Version + return + } + + // TODO(https://go.dev/issue/29228): we need to manually construct the + // version string when it is "(devel)" until #29228 is resolved. + var revision, at string + for _, s := range bi.Settings { + if s.Key == "vcs.revision" { + revision = s.Value + } + if s.Key == "vcs.time" { + at = s.Value + } + } + buf := strings.Builder{} + buf.WriteString("v0.0.0") + if revision != "" { + buf.WriteString("-") + buf.WriteString(revision[:12]) + } + if at != "" { + // commit time is of the form 2023-01-25T19:57:54Z + p, err := time.Parse(time.RFC3339, at) + if err == nil { + buf.WriteString("-") + buf.WriteString(p.Format("20060102150405")) + } + } + cfg.ScannerVersion = buf.String() +} diff --git a/vendor/golang.org/x/vuln/internal/scan/source.go b/vendor/golang.org/x/vuln/internal/scan/source.go new file mode 100644 index 000000000..f82a4db1d --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/source.go @@ -0,0 +1,124 @@ +// Copyright 2022 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 scan + +import ( + "context" + "fmt" + + "golang.org/x/tools/go/packages" + "golang.org/x/vuln/internal/client" + "golang.org/x/vuln/internal/derrors" + "golang.org/x/vuln/internal/govulncheck" + "golang.org/x/vuln/internal/vulncheck" +) + +// runSource reports vulnerabilities that affect the analyzed packages. +// +// Vulnerabilities can be called (affecting the package, because a vulnerable +// symbol is actually exercised) or just imported by the package +// (likely having a non-affecting outcome). +func runSource(ctx context.Context, handler govulncheck.Handler, cfg *config, client *client.Client, dir string) (err error) { + defer derrors.Wrap(&err, "govulncheck") + + if cfg.ScanLevel.WantPackages() && len(cfg.patterns) == 0 { + return nil // don't throw an error here + } + if !gomodExists(dir) { + return errNoGoMod + } + var pkgs []*packages.Package + var mods []*packages.Module + graph := vulncheck.NewPackageGraph(cfg.GoVersion) + pkgConfig := &packages.Config{ + Dir: dir, + Tests: cfg.test, + Env: cfg.env, + } + pkgs, mods, err = graph.LoadPackagesAndMods(pkgConfig, cfg.tags, cfg.patterns) + if err != nil { + if isGoVersionMismatchError(err) { + return fmt.Errorf("%v\n\n%v", errGoVersionMismatch, err) + } + return fmt.Errorf("loading packages: %w", err) + } + + if err := handler.Progress(sourceProgressMessage(pkgs, len(mods)-1, cfg.ScanLevel)); err != nil { + return err + } + + if cfg.ScanLevel.WantPackages() && len(pkgs) == 0 { + return nil // early exit + } + return vulncheck.Source(ctx, handler, pkgs, mods, &cfg.Config, client, graph) +} + +// sourceProgressMessage returns a string of the form +// +// "Scanning your code and P packages across M dependent modules for known vulnerabilities..." +// +// P is the number of strictly dependent packages of +// topPkgs and Y is the number of their modules. If P +// is 0, then the following message is returned +// +// "No packages matching the provided pattern." +func sourceProgressMessage(topPkgs []*packages.Package, mods int, mode govulncheck.ScanLevel) *govulncheck.Progress { + var pkgsPhrase, modsPhrase string + + if mode.WantPackages() { + if len(topPkgs) == 0 { + // The package pattern is valid, but no packages are matching. + // Example is pkg/strace/... (see #59623). + return &govulncheck.Progress{Message: "No packages matching the provided pattern."} + } + pkgs := depPkgs(topPkgs) + pkgsPhrase = fmt.Sprintf(" and %d package%s", pkgs, choose(pkgs != 1, "s", "")) + } + modsPhrase = fmt.Sprintf(" %d dependent module%s", mods, choose(mods != 1, "s", "")) + + msg := fmt.Sprintf("Scanning your code%s across%s for known vulnerabilities...", pkgsPhrase, modsPhrase) + return &govulncheck.Progress{Message: msg} +} + +// depPkgs returns the number of packages that topPkgs depend on +func depPkgs(topPkgs []*packages.Package) int { + tops := make(map[string]bool) + depPkgs := make(map[string]bool) + + for _, t := range topPkgs { + tops[t.PkgPath] = true + } + + var visit func(*packages.Package, bool) + visit = func(p *packages.Package, top bool) { + path := p.PkgPath + if depPkgs[path] { + return + } + if tops[path] && !top { + // A top package that is a dependency + // will not be in depPkgs, so we skip + // reiterating on it here. + return + } + + // We don't count a top-level package as + // a dependency even when they are used + // as a dependent package. + if !tops[path] { + depPkgs[path] = true + } + + for _, d := range p.Imports { + visit(d, false) + } + } + + for _, t := range topPkgs { + visit(t, true) + } + + return len(depPkgs) +} diff --git a/vendor/golang.org/x/vuln/cmd/govulncheck/stdlib.go b/vendor/golang.org/x/vuln/internal/scan/stdlib.go similarity index 86% rename from vendor/golang.org/x/vuln/cmd/govulncheck/stdlib.go rename to vendor/golang.org/x/vuln/internal/scan/stdlib.go index a7b5be8ac..19b9fb49f 100644 --- a/vendor/golang.org/x/vuln/cmd/govulncheck/stdlib.go +++ b/vendor/golang.org/x/vuln/internal/scan/stdlib.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package scan import ( "fmt" @@ -69,12 +69,3 @@ func finalDigitsIndex(s string) int { } return i + 1 } - -// importPathInStdlib reports whether the given import path could be part of the Go standard library, -// by reporting whether the first component lacks a '.'. -func importPathInStdlib(path string) bool { - if i := strings.IndexByte(path, '/'); i != -1 { - path = path[:i] - } - return !strings.Contains(path, ".") -} diff --git a/vendor/golang.org/x/vuln/internal/scan/template.go b/vendor/golang.org/x/vuln/internal/scan/template.go new file mode 100644 index 000000000..419b2eddb --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/template.go @@ -0,0 +1,287 @@ +// Copyright 2022 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 scan + +import ( + "go/token" + "io" + "path" + "sort" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "golang.org/x/vuln/internal/govulncheck" + "golang.org/x/vuln/internal/osv" +) + +type findingSummary struct { + *govulncheck.Finding + Compact string + OSV *osv.Entry +} + +type summaryCounters struct { + VulnerabilitiesCalled int + ModulesCalled int + VulnerabilitiesImported int + VulnerabilitiesRequired int + StdlibCalled bool +} + +func fixupFindings(osvs []*osv.Entry, findings []*findingSummary) { + for _, f := range findings { + f.OSV = getOSV(osvs, f.Finding.OSV) + } +} + +func groupByVuln(findings []*findingSummary) [][]*findingSummary { + return groupBy(findings, func(left, right *findingSummary) int { + return -strings.Compare(left.OSV.ID, right.OSV.ID) + }) +} + +func groupByModule(findings []*findingSummary) [][]*findingSummary { + return groupBy(findings, func(left, right *findingSummary) int { + return strings.Compare(left.Trace[0].Module, right.Trace[0].Module) + }) +} + +func groupBy(findings []*findingSummary, compare func(left, right *findingSummary) int) [][]*findingSummary { + switch len(findings) { + case 0: + return nil + case 1: + return [][]*findingSummary{findings} + } + sort.SliceStable(findings, func(i, j int) bool { + return compare(findings[i], findings[j]) < 0 + }) + result := [][]*findingSummary{} + first := 0 + for i, next := range findings { + if i == first { + continue + } + if compare(findings[first], next) != 0 { + result = append(result, findings[first:i]) + first = i + } + } + result = append(result, findings[first:]) + return result +} + +func isRequired(findings []*findingSummary) bool { + for _, f := range findings { + if f.Trace[0].Module != "" { + return true + } + } + return false +} + +func isImported(findings []*findingSummary) bool { + for _, f := range findings { + if f.Trace[0].Package != "" { + return true + } + } + return false +} + +func isCalled(findings []*findingSummary) bool { + for _, f := range findings { + if f.Trace[0].Function != "" { + return true + } + } + return false +} + +func getOSV(osvs []*osv.Entry, id string) *osv.Entry { + for _, entry := range osvs { + if entry.ID == id { + return entry + } + } + return &osv.Entry{ + ID: id, + DatabaseSpecific: &osv.DatabaseSpecific{}, + } +} + +func newFindingSummary(f *govulncheck.Finding) *findingSummary { + return &findingSummary{ + Finding: f, + Compact: compactTrace(f), + } +} + +// platforms returns a string describing the GOOS, GOARCH, +// or GOOS/GOARCH pairs that the vuln affects for a particular +// module mod. If it affects all of them, it returns the empty +// string. +// +// When mod is an empty string, returns platform information for +// all modules of e. +func platforms(mod string, e *osv.Entry) []string { + if e == nil { + return nil + } + platforms := map[string]bool{} + for _, a := range e.Affected { + if mod != "" && a.Module.Path != mod { + continue + } + for _, p := range a.EcosystemSpecific.Packages { + for _, os := range p.GOOS { + // In case there are no specific architectures, + // just list the os entries. + if len(p.GOARCH) == 0 { + platforms[os] = true + continue + } + // Otherwise, list all the os+arch combinations. + for _, arch := range p.GOARCH { + platforms[os+"/"+arch] = true + } + } + // Cover the case where there are no specific + // operating systems listed. + if len(p.GOOS) == 0 { + for _, arch := range p.GOARCH { + platforms[arch] = true + } + } + } + } + var keys []string + for k := range platforms { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +func posToString(p *govulncheck.Position) string { + if p == nil || p.Line <= 0 { + return "" + } + return token.Position{ + Filename: AbsRelShorter(p.Filename), + Offset: p.Offset, + Line: p.Line, + Column: p.Column, + }.String() +} + +func symbol(frame *govulncheck.Frame, short bool) string { + buf := &strings.Builder{} + addSymbolName(buf, frame, short) + return buf.String() +} + +// compactTrace returns a short description of the call stack. +// It prefers to show you the edge from the top module to other code, along with +// the vulnerable symbol. +// Where the vulnerable symbol directly called by the users code, it will only +// show those two points. +// If the vulnerable symbol is in the users code, it will show the entry point +// and the vulnerable symbol. +func compactTrace(finding *govulncheck.Finding) string { + if len(finding.Trace) < 1 { + return "" + } + iTop := len(finding.Trace) - 1 + topModule := finding.Trace[iTop].Module + // search for the exit point of the top module + for i, frame := range finding.Trace { + if frame.Module == topModule { + iTop = i + break + } + } + + if iTop == 0 { + // all in one module, reset to the end + iTop = len(finding.Trace) - 1 + } + + buf := &strings.Builder{} + topPos := posToString(finding.Trace[iTop].Position) + if topPos != "" { + buf.WriteString(topPos) + buf.WriteString(": ") + } + + if iTop > 0 { + addSymbolName(buf, finding.Trace[iTop], true) + buf.WriteString(" calls ") + } + if iTop > 1 { + addSymbolName(buf, finding.Trace[iTop-1], true) + buf.WriteString(", which") + if iTop > 2 { + buf.WriteString(" eventually") + } + buf.WriteString(" calls ") + } + addSymbolName(buf, finding.Trace[0], true) + return buf.String() +} + +// notIdentifier reports whether ch is an invalid identifier character. +func notIdentifier(ch rune) bool { + return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || + '0' <= ch && ch <= '9' || + ch == '_' || + ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch))) +} + +// importPathToAssumedName is taken from goimports, it works out the natural imported name +// for a package. +// This is used to get a shorter identifier in the compact stack trace +func importPathToAssumedName(importPath string) string { + base := path.Base(importPath) + if strings.HasPrefix(base, "v") { + if _, err := strconv.Atoi(base[1:]); err == nil { + dir := path.Dir(importPath) + if dir != "." { + base = path.Base(dir) + } + } + } + base = strings.TrimPrefix(base, "go-") + if i := strings.IndexFunc(base, notIdentifier); i >= 0 { + base = base[:i] + } + return base +} + +func addSymbolName(w io.Writer, frame *govulncheck.Frame, short bool) { + if frame.Function == "" { + return + } + if frame.Package != "" { + pkg := frame.Package + if short { + pkg = importPathToAssumedName(frame.Package) + } + io.WriteString(w, pkg) + io.WriteString(w, ".") + } + if frame.Receiver != "" { + if frame.Receiver[0] == '*' { + io.WriteString(w, frame.Receiver[1:]) + } else { + io.WriteString(w, frame.Receiver) + } + io.WriteString(w, ".") + } + funcname := strings.Split(frame.Function, "$")[0] + io.WriteString(w, funcname) +} diff --git a/vendor/golang.org/x/vuln/internal/scan/text.go b/vendor/golang.org/x/vuln/internal/scan/text.go new file mode 100644 index 000000000..29e1eceee --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/text.go @@ -0,0 +1,481 @@ +// Copyright 2022 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 scan + +import ( + "fmt" + "io" + "strings" + + "golang.org/x/vuln/internal" + "golang.org/x/vuln/internal/govulncheck" + "golang.org/x/vuln/internal/osv" + "golang.org/x/vuln/internal/vulncheck" +) + +type style int + +const ( + defaultStyle = style(iota) + osvCalledStyle + osvImportedStyle + detailsStyle + sectionStyle + keyStyle + valueStyle +) + +// NewtextHandler returns a handler that writes govulncheck output as text. +func NewTextHandler(w io.Writer) *TextHandler { + return &TextHandler{w: w} +} + +type TextHandler struct { + w io.Writer + osvs []*osv.Entry + findings []*findingSummary + scanLevel govulncheck.ScanLevel + + err error + + showColor bool + showTraces bool + showVersion bool + showAllVulns bool +} + +const ( + detailsMessage = `For details, see https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck.` + + binaryProgressMessage = `Scanning your binary for known vulnerabilities...` + + noVulnsMessage = `No vulnerabilities found.` + + noOtherVulnsMessage = `No other vulnerabilities found.` + + verboseMessage = `'-show verbose' for more details` + + symbolMessage = `'-scan symbol' for more fine grained vulnerability detection` +) + +func (h *TextHandler) Show(show []string) { + for _, show := range show { + switch show { + case "traces": + h.showTraces = true + case "color": + h.showColor = true + case "version": + h.showVersion = true + case "verbose": + h.showAllVulns = true + } + } +} + +func Flush(h govulncheck.Handler) error { + if th, ok := h.(interface{ Flush() error }); ok { + return th.Flush() + } + return nil +} + +func (h *TextHandler) Flush() error { + if len(h.findings) == 0 { + h.print(noVulnsMessage + "\n") + } else { + fixupFindings(h.osvs, h.findings) + counters := h.allVulns(h.findings) + h.summary(counters) + } + if h.err != nil { + return h.err + } + // We found vulnerabilities when the findings' level matches the scan level. + if (isCalled(h.findings) && h.scanLevel == govulncheck.ScanLevelSymbol) || + (isImported(h.findings) && h.scanLevel == govulncheck.ScanLevelPackage) || + (isRequired(h.findings) && h.scanLevel == govulncheck.ScanLevelModule) { + return errVulnerabilitiesFound + } + + return nil +} + +// Config writes version information only if --version was set. +func (h *TextHandler) Config(config *govulncheck.Config) error { + if config.ScanLevel != "" { + h.scanLevel = config.ScanLevel + } + if !h.showVersion { + return nil + } + if config.GoVersion != "" { + h.style(keyStyle, "Go: ") + h.print(config.GoVersion, "\n") + } + if config.ScannerName != "" { + h.style(keyStyle, "Scanner: ") + h.print(config.ScannerName) + if config.ScannerVersion != "" { + h.print(`@`, config.ScannerVersion) + } + h.print("\n") + } + if config.DB != "" { + h.style(keyStyle, "DB: ") + h.print(config.DB, "\n") + if config.DBLastModified != nil { + h.style(keyStyle, "DB updated: ") + h.print(*config.DBLastModified, "\n") + } + } + h.print("\n") + return h.err +} + +// Progress writes progress updates during govulncheck execution. +func (h *TextHandler) Progress(progress *govulncheck.Progress) error { + h.print(progress.Message, "\n\n") + return h.err +} + +// OSV gathers osv entries to be written. +func (h *TextHandler) OSV(entry *osv.Entry) error { + h.osvs = append(h.osvs, entry) + return nil +} + +// Finding gathers vulnerability findings to be written. +func (h *TextHandler) Finding(finding *govulncheck.Finding) error { + if err := validateFindings(finding); err != nil { + return err + } + h.findings = append(h.findings, newFindingSummary(finding)) + return nil +} + +func (h *TextHandler) allVulns(findings []*findingSummary) summaryCounters { + byVuln := groupByVuln(findings) + var called, imported, required [][]*findingSummary + mods := map[string]struct{}{} + stdlibCalled := false + for _, findings := range byVuln { + switch { + case isStdFindings(findings): + if isCalled(findings) { + called = append(called, findings) + stdlibCalled = true + } else { + required = append(required, findings) + } + case isCalled(findings): + called = append(called, findings) + mods[findings[0].Trace[0].Module] = struct{}{} + case isImported(findings): + imported = append(imported, findings) + default: + required = append(required, findings) + } + } + + if h.scanLevel.WantSymbols() { + h.style(sectionStyle, "=== Symbol Results ===\n\n") + if len(called) == 0 { + h.print(noVulnsMessage, "\n\n") + } + for index, findings := range called { + h.vulnerability(index, findings) + } + } + + if h.scanLevel == govulncheck.ScanLevelPackage || (h.scanLevel.WantPackages() && h.showAllVulns) { + h.style(sectionStyle, "=== Package Results ===\n\n") + if len(imported) == 0 { + h.print(choose(!h.scanLevel.WantSymbols(), noVulnsMessage, noOtherVulnsMessage), "\n\n") + } + for index, findings := range imported { + h.vulnerability(index, findings) + } + } + + if h.showAllVulns || h.scanLevel == govulncheck.ScanLevelModule { + h.style(sectionStyle, "=== Module Results ===\n\n") + if len(required) == 0 { + h.print(choose(!h.scanLevel.WantPackages(), noVulnsMessage, noOtherVulnsMessage), "\n\n") + } + for index, findings := range required { + h.vulnerability(index, findings) + } + } + + return summaryCounters{ + VulnerabilitiesCalled: len(called), + VulnerabilitiesImported: len(imported), + VulnerabilitiesRequired: len(required), + ModulesCalled: len(mods), + StdlibCalled: stdlibCalled, + } +} + +func (h *TextHandler) vulnerability(index int, findings []*findingSummary) { + h.style(keyStyle, "Vulnerability") + h.print(" #", index+1, ": ") + if isCalled(findings) { + h.style(osvCalledStyle, findings[0].OSV.ID) + } else { + h.style(osvImportedStyle, findings[0].OSV.ID) + } + h.print("\n") + h.style(detailsStyle) + description := findings[0].OSV.Summary + if description == "" { + description = findings[0].OSV.Details + } + h.wrap(" ", description, 80) + h.style(defaultStyle) + h.print("\n") + h.style(keyStyle, " More info:") + h.print(" ", findings[0].OSV.DatabaseSpecific.URL, "\n") + + byModule := groupByModule(findings) + first := true + for _, module := range byModule { + //TODO: this assumes all traces on a module are found and fixed at the same versions + lastFrame := module[0].Trace[0] + mod := lastFrame.Module + path := lastFrame.Module + if path == internal.GoStdModulePath { + path = lastFrame.Package + } + foundVersion := moduleVersionString(lastFrame.Module, lastFrame.Version) + fixedVersion := moduleVersionString(lastFrame.Module, module[0].FixedVersion) + if !first { + h.print("\n") + } + first = false + h.print(" ") + if mod == internal.GoStdModulePath { + h.print("Standard library") + } else { + h.style(keyStyle, "Module: ") + h.print(mod) + } + h.print("\n ") + h.style(keyStyle, "Found in: ") + h.print(path, "@", foundVersion, "\n ") + h.style(keyStyle, "Fixed in: ") + if fixedVersion != "" { + h.print(path, "@", fixedVersion) + } else { + h.print("N/A") + } + h.print("\n") + platforms := platforms(mod, module[0].OSV) + if len(platforms) > 0 { + h.style(keyStyle, " Platforms: ") + for ip, p := range platforms { + if ip > 0 { + h.print(", ") + } + h.print(p) + } + h.print("\n") + } + h.traces(module) + } + h.print("\n") +} + +func (h *TextHandler) traces(traces []*findingSummary) { + first := true + count := 1 + for _, entry := range traces { + if entry.Compact == "" { + continue + } + if first { + h.style(keyStyle, " Example traces found:\n") + } + first = false + + h.print(" #", count, ": ") + count++ + if !h.showTraces { + h.print(entry.Compact, "\n") + } else { + h.print("for function ", symbol(entry.Trace[0], false), "\n") + for i := len(entry.Trace) - 1; i >= 0; i-- { + t := entry.Trace[i] + h.print(" ") + if t.Position != nil { + h.print(posToString(t.Position), ": ") + } + h.print(symbol(t, false), "\n") + } + } + } +} + +func (h *TextHandler) summary(c summaryCounters) { + // print short summary of findings identified at the desired level of scan precision + var vulnCount int + h.print("Your code ", choose(h.scanLevel.WantSymbols(), "is", "may be"), " affected by ") + switch h.scanLevel { + case govulncheck.ScanLevelSymbol: + vulnCount = c.VulnerabilitiesCalled + case govulncheck.ScanLevelPackage: + vulnCount = c.VulnerabilitiesImported + case govulncheck.ScanLevelModule: + vulnCount = c.VulnerabilitiesRequired + } + h.style(valueStyle, vulnCount) + h.print(choose(vulnCount == 1, ` vulnerability`, ` vulnerabilities`)) + if h.scanLevel.WantSymbols() { + h.print(choose(c.ModulesCalled > 0 || c.StdlibCalled, ` from `, ``)) + if c.ModulesCalled > 0 { + h.style(valueStyle, c.ModulesCalled) + h.print(choose(c.ModulesCalled == 1, ` module`, ` modules`)) + } + if c.StdlibCalled { + if c.ModulesCalled != 0 { + h.print(` and `) + } + h.print(`the Go standard library`) + } + } + h.print(".\n") + + // print summary for vulnerabilities found at other levels of scan precision + if other := h.summaryOtherVulns(c); other != "" { + h.wrap("", other, 80) + h.print("\n") + } + + // print suggested flags for more/better info depending on scan level and if in verbose mode + if sugg := h.summarySuggestion(); sugg != "" { + h.wrap("", sugg, 80) + h.print("\n") + } +} + +func (h *TextHandler) summaryOtherVulns(c summaryCounters) string { + var summary strings.Builder + if c.VulnerabilitiesRequired+c.VulnerabilitiesImported == 0 { + summary.WriteString("This scan found no other vulnerabilities in ") + if h.scanLevel.WantSymbols() { + summary.WriteString("packages you import or ") + } + summary.WriteString("modules you require.") + } else { + summary.WriteString(choose(h.scanLevel.WantPackages(), "This scan also found ", "")) + if h.scanLevel.WantSymbols() { + summary.WriteString(fmt.Sprint(c.VulnerabilitiesImported)) + summary.WriteString(choose(c.VulnerabilitiesImported == 1, ` vulnerability `, ` vulnerabilities `)) + summary.WriteString("in packages you import and ") + } + if h.scanLevel.WantPackages() { + summary.WriteString(fmt.Sprint(c.VulnerabilitiesRequired)) + summary.WriteString(choose(c.VulnerabilitiesRequired == 1, ` vulnerability `, ` vulnerabilities `)) + summary.WriteString("in modules you require") + summary.WriteString(choose(h.scanLevel.WantSymbols(), ", but your code doesn't appear to call these vulnerabilities.", ".")) + } + } + return summary.String() +} + +func (h *TextHandler) summarySuggestion() string { + var sugg strings.Builder + switch h.scanLevel { + case govulncheck.ScanLevelSymbol: + if !h.showAllVulns { + sugg.WriteString("Use " + verboseMessage + ".") + } + case govulncheck.ScanLevelPackage: + sugg.WriteString("Use " + symbolMessage) + if !h.showAllVulns { + sugg.WriteString(" and " + verboseMessage) + } + sugg.WriteString(".") + case govulncheck.ScanLevelModule: + sugg.WriteString("Use " + symbolMessage + ".") + } + return sugg.String() +} + +func (h *TextHandler) style(style style, values ...any) { + if h.showColor { + switch style { + default: + h.print(colorReset) + case osvCalledStyle: + h.print(colorBold, fgRed) + case osvImportedStyle: + h.print(colorBold, fgGreen) + case detailsStyle: + h.print(colorFaint) + case sectionStyle: + h.print(fgBlue) + case keyStyle: + h.print(colorFaint, fgYellow) + case valueStyle: + h.print(colorBold, fgCyan) + } + } + h.print(values...) + if h.showColor && len(values) > 0 { + h.print(colorReset) + } +} + +func (h *TextHandler) print(values ...any) int { + total, w := 0, 0 + for _, v := range values { + if h.err != nil { + return total + } + // do we need to specialize for some types, like time? + w, h.err = fmt.Fprint(h.w, v) + total += w + } + return total +} + +// wrap wraps s to fit in maxWidth by breaking it into lines at whitespace. If a +// single word is longer than maxWidth, it is retained as its own line. +func (h *TextHandler) wrap(indent string, s string, maxWidth int) { + w := 0 + for _, f := range strings.Fields(s) { + if w > 0 && w+len(f)+1 > maxWidth { + // line would be too long with this word + h.print("\n") + w = 0 + } + if w == 0 { + // first field on line, indent + w = h.print(indent) + } else { + // not first word, space separate + w += h.print(" ") + } + // now write the word + w += h.print(f) + } +} + +func choose[t any](b bool, yes, no t) t { + if b { + return yes + } + return no +} + +func isStdFindings(findings []*findingSummary) bool { + for _, f := range findings { + if vulncheck.IsStdPackage(f.Trace[0].Package) || f.Trace[0].Module == internal.GoStdModulePath { + return true + } + } + return false +} diff --git a/vendor/golang.org/x/vuln/internal/scan/util.go b/vendor/golang.org/x/vuln/internal/scan/util.go new file mode 100644 index 000000000..420703061 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/scan/util.go @@ -0,0 +1,59 @@ +// Copyright 2022 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 scan + +import ( + "fmt" + "os" + "os/exec" + + "golang.org/x/vuln/internal" + "golang.org/x/vuln/internal/govulncheck" +) + +// validateFindings checks that the supplied findings all obey the protocol +// rules. +func validateFindings(findings ...*govulncheck.Finding) error { + for _, f := range findings { + if f.OSV == "" { + return fmt.Errorf("invalid finding: all findings must have an associated OSV") + } + if len(f.Trace) < 1 { + return fmt.Errorf("invalid finding: all callstacks must have at least one frame") + } + for _, frame := range f.Trace { + if frame.Version != "" && frame.Module == "" { + return fmt.Errorf("invalid finding: if Frame.Version is set, Frame.Module must also be") + } + if frame.Package != "" && frame.Module == "" { + return fmt.Errorf("invalid finding: if Frame.Package is set, Frame.Module must also be") + } + if frame.Function != "" && frame.Package == "" { + return fmt.Errorf("invalid finding: if Frame.Function is set, Frame.Package must also be") + } + } + } + return nil +} + +func moduleVersionString(modulePath, version string) string { + if version == "" { + return "" + } + if modulePath == internal.GoStdModulePath || modulePath == internal.GoCmdModulePath { + version = semverToGoTag(version) + } + return version +} + +func gomodExists(dir string) bool { + cmd := exec.Command("go", "env", "GOMOD") + cmd.Dir = dir + out, err := cmd.Output() + output := string(out) + // If module-aware mode is enabled, but there is no go.mod, GOMOD will be os.DevNull + // If module-aware mode is disabled, GOMOD will be the empty string. + return err == nil && !(output == os.DevNull || output == "") +} diff --git a/vendor/golang.org/x/vuln/internal/semver/affects.go b/vendor/golang.org/x/vuln/internal/semver/affects.go new file mode 100644 index 000000000..03ea6fd78 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/semver/affects.go @@ -0,0 +1,94 @@ +// Copyright 2023 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 semver + +import ( + "sort" + + "golang.org/x/vuln/internal/osv" +) + +func Affects(a []osv.Range, v string) bool { + if len(a) == 0 { + // No ranges implies all versions are affected + return true + } + var semverRangePresent bool + for _, r := range a { + if r.Type != osv.RangeTypeSemver { + continue + } + semverRangePresent = true + if ContainsSemver(r, v) { + return true + } + } + // If there were no semver ranges present we + // assume that all semvers are affected, similarly + // to how to we assume all semvers are affected + // if there are no ranges at all. + return !semverRangePresent +} + +// ContainsSemver checks if semver version v is in the +// range encoded by ar. If ar is not a semver range, +// returns false. A range is interpreted as a left-closed +// and right-open interval. +// +// Assumes that +// - exactly one of Introduced or Fixed fields is set +// - ranges in ar are not overlapping +// - beginning of time is encoded with .Introduced="0" +// - no-fix is not an event, as opposed to being an +// event where Introduced="" and Fixed="" +func ContainsSemver(ar osv.Range, v string) bool { + if ar.Type != osv.RangeTypeSemver { + return false + } + if len(ar.Events) == 0 { + return true + } + + // Strip and then add the semver prefix so we can support bare versions, + // versions prefixed with 'v', and versions prefixed with 'go'. + v = canonicalizeSemverPrefix(v) + + // Sort events by semver versions. Event for beginning + // of time, if present, always comes first. + sort.SliceStable(ar.Events, func(i, j int) bool { + e1 := ar.Events[i] + v1 := e1.Introduced + if v1 == "0" { + // -inf case. + return true + } + if e1.Fixed != "" { + v1 = e1.Fixed + } + + e2 := ar.Events[j] + v2 := e2.Introduced + if v2 == "0" { + // -inf case. + return false + } + if e2.Fixed != "" { + v2 = e2.Fixed + } + + return Less(v1, v2) + }) + + var affected bool + for _, e := range ar.Events { + if !affected && e.Introduced != "" { + affected = e.Introduced == "0" || !Less(v, e.Introduced) + } else if affected && e.Fixed != "" { + affected = Less(v, e.Fixed) + } + } + + return affected +} diff --git a/vendor/golang.org/x/vuln/internal/semver/fixed.go b/vendor/golang.org/x/vuln/internal/semver/fixed.go new file mode 100644 index 000000000..bd29c407d --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/semver/fixed.go @@ -0,0 +1,36 @@ +// Copyright 2023 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 semver + +import "golang.org/x/vuln/internal/osv" + +// NonSupersededFix returns a fixed version from ranges +// that is not superseded by any other fix or any other +// introduction of a vulnerability. Returns "" in case +// there is no such fixed version. +func NonSupersededFix(ranges []osv.Range) string { + var latestFixed string + for _, r := range ranges { + if r.Type == "SEMVER" { + for _, e := range r.Events { + fixed := e.Fixed + if fixed != "" && Less(latestFixed, fixed) { + latestFixed = fixed + } + } + + // If the vulnerability was re-introduced after the latest fix + // we found, there is no latest fix for this range. + for _, e := range r.Events { + introduced := e.Introduced + if introduced != "" && introduced != "0" && Less(latestFixed, introduced) { + latestFixed = "" + break + } + } + } + } + return latestFixed +} diff --git a/vendor/golang.org/x/vuln/internal/semver/semver.go b/vendor/golang.org/x/vuln/internal/semver/semver.go index 890ecd92e..fe0f701b0 100644 --- a/vendor/golang.org/x/vuln/internal/semver/semver.go +++ b/vendor/golang.org/x/vuln/internal/semver/semver.go @@ -9,6 +9,8 @@ package semver import ( "regexp" "strings" + + "golang.org/x/mod/semver" ) // addSemverPrefix adds a 'v' prefix to s if it isn't already prefixed @@ -29,14 +31,26 @@ func removeSemverPrefix(s string) string { return s } -// CanonicalizeSemverPrefix turns a SEMVER string into the canonical +// canonicalizeSemverPrefix turns a SEMVER string into the canonical // representation using the 'v' prefix, as used by the OSV format. // Input may be a bare SEMVER ("1.2.3"), Go prefixed SEMVER ("go1.2.3"), // or already canonical SEMVER ("v1.2.3"). -func CanonicalizeSemverPrefix(s string) string { +func canonicalizeSemverPrefix(s string) string { return addSemverPrefix(removeSemverPrefix(s)) } +// Less returns whether v1 < v2, where v1 and v2 are +// semver versions with either a "v", "go" or no prefix. +func Less(v1, v2 string) bool { + return semver.Compare(canonicalizeSemverPrefix(v1), canonicalizeSemverPrefix(v2)) < 0 +} + +// Valid returns whether v is valid semver, allowing +// either a "v", "go" or no prefix. +func Valid(v string) bool { + return semver.IsValid(canonicalizeSemverPrefix(v)) +} + var ( // Regexp for matching go tags. The groups are: // 1 the major.minor version diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/binary.go b/vendor/golang.org/x/vuln/internal/vulncheck/binary.go new file mode 100644 index 000000000..71ccc8ab7 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/binary.go @@ -0,0 +1,168 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.18 +// +build go1.18 + +package vulncheck + +import ( + "context" + "fmt" + "sort" + + "golang.org/x/tools/go/packages" + "golang.org/x/vuln/internal" + "golang.org/x/vuln/internal/buildinfo" + "golang.org/x/vuln/internal/client" + "golang.org/x/vuln/internal/govulncheck" +) + +// Bin is an abstraction of Go binary containing +// minimal information needed by govulncheck. +type Bin struct { + Modules []*packages.Module `json:"modules,omitempty"` + PkgSymbols []buildinfo.Symbol `json:"pkgSymbols,omitempty"` + GoVersion string `json:"goVersion,omitempty"` + GOOS string `json:"goos,omitempty"` + GOARCH string `json:"goarch,omitempty"` +} + +// Binary detects presence of vulnerable symbols in bin and +// emits findings to handler. +func Binary(ctx context.Context, handler govulncheck.Handler, bin *Bin, cfg *govulncheck.Config, client *client.Client) error { + vr, err := binary(ctx, handler, bin, cfg, client) + if err != nil { + return err + } + if cfg.ScanLevel.WantSymbols() { + return emitCallFindings(handler, binaryCallstacks(vr)) + } + return nil +} + +// binary detects presence of vulnerable symbols in bin. +// It does not compute call graphs so the corresponding +// info in Result will be empty. +func binary(ctx context.Context, handler govulncheck.Handler, bin *Bin, cfg *govulncheck.Config, client *client.Client) (*Result, error) { + graph := NewPackageGraph(bin.GoVersion) + graph.AddModules(bin.Modules...) + mods := append(bin.Modules, graph.GetModule(internal.GoStdModulePath)) + + mv, err := FetchVulnerabilities(ctx, client, mods) + if err != nil { + return nil, err + } + + // Emit OSV entries immediately in their raw unfiltered form. + if err := emitOSVs(handler, mv); err != nil { + return nil, err + } + + if bin.GOOS == "" || bin.GOARCH == "" { + fmt.Printf("warning: failed to extract build system specification GOOS: %s GOARCH: %s\n", bin.GOOS, bin.GOARCH) + } + affVulns := affectingVulnerabilities(mv, bin.GOOS, bin.GOARCH) + if err := emitModuleFindings(handler, affVulns); err != nil { + return nil, err + } + + if !cfg.ScanLevel.WantPackages() || len(affVulns) == 0 { + return &Result{}, nil + } + + // Group symbols per package to avoid querying affVulns all over again. + var pkgSymbols map[string][]string + if len(bin.PkgSymbols) == 0 { + // The binary exe is stripped. We currently cannot detect inlined + // symbols for stripped binaries (see #57764), so we report + // vulnerabilities at the go.mod-level precision. + pkgSymbols = allKnownVulnerableSymbols(affVulns) + } else { + pkgSymbols = make(map[string][]string) + for _, sym := range bin.PkgSymbols { + pkgSymbols[sym.Pkg] = append(pkgSymbols[sym.Pkg], sym.Name) + } + } + + impVulns := binImportedVulnPackages(graph, pkgSymbols, affVulns) + // Emit information on imported vulnerable packages now to + // mimic behavior of source. + if err := emitPackageFindings(handler, impVulns); err != nil { + return nil, err + } + + // Return result immediately if not in symbol mode to mimic the + // behavior of source. + if !cfg.ScanLevel.WantSymbols() || len(impVulns) == 0 { + return &Result{Vulns: impVulns}, nil + } + + symVulns := binVulnSymbols(graph, pkgSymbols, affVulns) + return &Result{Vulns: symVulns}, nil +} + +func binImportedVulnPackages(graph *PackageGraph, pkgSymbols map[string][]string, affVulns affectingVulns) []*Vuln { + var vulns []*Vuln + for pkg := range pkgSymbols { + for _, osv := range affVulns.ForPackage(pkg) { + vuln := &Vuln{ + OSV: osv, + Package: graph.GetPackage(pkg), + } + vulns = append(vulns, vuln) + } + } + return vulns +} + +func binVulnSymbols(graph *PackageGraph, pkgSymbols map[string][]string, affVulns affectingVulns) []*Vuln { + var vulns []*Vuln + for pkg, symbols := range pkgSymbols { + // sort symbols for deterministic results + sort.SliceStable(symbols, func(i, j int) bool { return symbols[i] < symbols[j] }) + for _, symbol := range symbols { + for _, osv := range affVulns.ForSymbol(pkg, symbol) { + vuln := &Vuln{ + OSV: osv, + Symbol: symbol, + Package: graph.GetPackage(pkg), + } + vulns = append(vulns, vuln) + } + } + } + return vulns +} + +// allKnownVulnerableSymbols returns all known vulnerable symbols for packages in graph. +// If all symbols of a package are vulnerable, that is modeled as a wild car symbol "/*". +func allKnownVulnerableSymbols(affVulns affectingVulns) map[string][]string { + pkgSymbols := make(map[string][]string) + for _, mv := range affVulns { + for _, osv := range mv.Vulns { + for _, affected := range osv.Affected { + for _, p := range affected.EcosystemSpecific.Packages { + syms := p.Symbols + if len(syms) == 0 { + // If every symbol of pkg is vulnerable, we would ideally + // compute every symbol mentioned in the pkg and then add + // Vuln entry for it, just as we do in Source. However, + // we don't have code of pkg here and we don't even have + // pkg symbols used in stripped binary, so we add a placeholder + // symbol. + // + // Note: this should not affect output of govulncheck since + // in binary mode no symbol/call stack information is + // communicated back to the user. + syms = []string{fmt.Sprintf("%s/*", p.Path)} + } + + pkgSymbols[p.Path] = append(pkgSymbols[p.Path], syms...) + } + } + } + } + return pkgSymbols +} diff --git a/vendor/golang.org/x/vuln/vulncheck/doc.go b/vendor/golang.org/x/vuln/internal/vulncheck/doc.go similarity index 94% rename from vendor/golang.org/x/vuln/vulncheck/doc.go rename to vendor/golang.org/x/vuln/internal/vulncheck/doc.go index f141c0f57..3f19e2995 100644 --- a/vendor/golang.org/x/vuln/vulncheck/doc.go +++ b/vendor/golang.org/x/vuln/internal/vulncheck/doc.go @@ -29,9 +29,9 @@ must have been compiled with Go 1.18 or greater. Both [Source] and [Binary] require information about known vulnerabilities in the form of a vulnerability database, -specifically a [golang.org/x/vuln/client.Client]. +specifically a [golang.org/x/vuln/internal/client.Client]. The vulnerabilities -are modeled using the [golang.org/x/vuln/osv] format. +are modeled using the [golang.org/x/vuln/internal/osv] format. # Results diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/emit.go b/vendor/golang.org/x/vuln/internal/vulncheck/emit.go new file mode 100644 index 000000000..aeee0f75d --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/emit.go @@ -0,0 +1,163 @@ +// Copyright 2023 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 vulncheck + +import ( + "go/token" + "sort" + + "golang.org/x/tools/go/packages" + "golang.org/x/vuln/internal" + "golang.org/x/vuln/internal/govulncheck" + "golang.org/x/vuln/internal/osv" +) + +// emitOSVs emits all OSV vuln entries in modVulns to handler. +func emitOSVs(handler govulncheck.Handler, modVulns []*ModVulns) error { + for _, mv := range modVulns { + for _, v := range mv.Vulns { + if err := handler.OSV(v); err != nil { + return err + } + } + } + return nil +} + +// emitModuleFindings emits module-level findings for vulnerabilities in modVulns. +func emitModuleFindings(handler govulncheck.Handler, affVulns affectingVulns) error { + for _, vuln := range affVulns { + for _, osv := range vuln.Vulns { + if err := handler.Finding(&govulncheck.Finding{ + OSV: osv.ID, + FixedVersion: FixedVersion(modPath(vuln.Module), modVersion(vuln.Module), osv.Affected), + Trace: []*govulncheck.Frame{frameFromModule(vuln.Module, osv.Affected)}, + }); err != nil { + return err + } + } + } + return nil +} + +// emitPackageFinding emits package-level findings fod vulnerabilities in vulns. +func emitPackageFindings(handler govulncheck.Handler, vulns []*Vuln) error { + for _, v := range vulns { + if err := handler.Finding(&govulncheck.Finding{ + OSV: v.OSV.ID, + FixedVersion: FixedVersion(modPath(v.Package.Module), modVersion(v.Package.Module), v.OSV.Affected), + Trace: []*govulncheck.Frame{frameFromPackage(v.Package)}, + }); err != nil { + return err + } + } + return nil +} + +// emitCallFindings emits call-level findings for vulnerabilities +// that have a call stack in callstacks. +func emitCallFindings(handler govulncheck.Handler, callstacks map[*Vuln]CallStack) error { + var vulns []*Vuln + for v := range callstacks { + vulns = append(vulns, v) + } + + sort.SliceStable(vulns, func(i, j int) bool { + return vulns[i].Symbol < vulns[j].Symbol + }) + + for _, vuln := range vulns { + stack := callstacks[vuln] + if stack == nil { + continue + } + fixed := FixedVersion(modPath(vuln.Package.Module), modVersion(vuln.Package.Module), vuln.OSV.Affected) + if err := handler.Finding(&govulncheck.Finding{ + OSV: vuln.OSV.ID, + FixedVersion: fixed, + Trace: traceFromEntries(stack), + }); err != nil { + return err + } + } + return nil +} + +// traceFromEntries creates a sequence of +// frames from vcs. Position of a Frame is the +// call position of the corresponding stack entry. +func traceFromEntries(vcs CallStack) []*govulncheck.Frame { + var frames []*govulncheck.Frame + for i := len(vcs) - 1; i >= 0; i-- { + e := vcs[i] + fr := frameFromPackage(e.Function.Package) + fr.Function = e.Function.Name + fr.Receiver = e.Function.Receiver() + isSink := i == (len(vcs) - 1) + fr.Position = posFromStackEntry(e, isSink) + frames = append(frames, fr) + } + return frames +} + +func posFromStackEntry(e StackEntry, sink bool) *govulncheck.Position { + var p *token.Position + if sink && e.Function != nil && e.Function.Pos != nil { + // For sinks, i.e., vulns we take the position + // of the symbol. + p = e.Function.Pos + } else if e.Call != nil && e.Call.Pos != nil { + // Otherwise, we take the position of + // the call statement. + p = e.Call.Pos + } + + if p == nil { + return nil + } + return &govulncheck.Position{ + Filename: p.Filename, + Offset: p.Offset, + Line: p.Line, + Column: p.Column, + } +} + +func frameFromPackage(pkg *packages.Package) *govulncheck.Frame { + fr := &govulncheck.Frame{} + if pkg != nil { + fr.Module = pkg.Module.Path + fr.Version = pkg.Module.Version + fr.Package = pkg.PkgPath + } + if pkg.Module.Replace != nil { + fr.Module = pkg.Module.Replace.Path + fr.Version = pkg.Module.Replace.Version + } + return fr +} + +func frameFromModule(mod *packages.Module, affected []osv.Affected) *govulncheck.Frame { + fr := &govulncheck.Frame{ + Module: mod.Path, + Version: mod.Version, + } + + if mod.Path == internal.GoStdModulePath { + for _, a := range affected { + if a.Module.Path != mod.Path { + continue + } + fr.Package = a.EcosystemSpecific.Packages[0].Path + } + } + + if mod.Replace != nil { + fr.Module = mod.Replace.Path + fr.Version = mod.Replace.Version + } + + return fr +} diff --git a/vendor/golang.org/x/vuln/vulncheck/entries.go b/vendor/golang.org/x/vuln/internal/vulncheck/entries.go similarity index 84% rename from vendor/golang.org/x/vuln/vulncheck/entries.go rename to vendor/golang.org/x/vuln/internal/vulncheck/entries.go index 834d5901a..3d46f6cab 100644 --- a/vendor/golang.org/x/vuln/vulncheck/entries.go +++ b/vendor/golang.org/x/vuln/internal/vulncheck/entries.go @@ -10,6 +10,12 @@ import ( "golang.org/x/tools/go/ssa" ) +// entryPoints returns functions of topPackages considered entry +// points of govulncheck analysis: main, inits, and exported methods +// and functions. +// +// TODO(https://go.dev/issue/57221): currently, entry functions +// that are generics are not considered an entry point. func entryPoints(topPackages []*ssa.Package) []*ssa.Function { var entries []*ssa.Function for _, pkg := range topPackages { diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/fetch.go b/vendor/golang.org/x/vuln/internal/vulncheck/fetch.go new file mode 100644 index 000000000..700a7f998 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/fetch.go @@ -0,0 +1,42 @@ +// Copyright 2021 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 vulncheck + +import ( + "context" + "fmt" + + "golang.org/x/tools/go/packages" + "golang.org/x/vuln/internal/client" +) + +// FetchVulnerabilities fetches vulnerabilities that affect the supplied modules. +func FetchVulnerabilities(ctx context.Context, c *client.Client, modules []*packages.Module) ([]*ModVulns, error) { + mreqs := make([]*client.ModuleRequest, len(modules)) + for i, mod := range modules { + modPath := mod.Path + if mod.Replace != nil { + modPath = mod.Replace.Path + } + mreqs[i] = &client.ModuleRequest{ + Path: modPath, + } + } + resps, err := c.ByModules(ctx, mreqs) + if err != nil { + return nil, fmt.Errorf("fetching vulnerabilities: %v", err) + } + var mv []*ModVulns + for i, resp := range resps { + if len(resp.Entries) == 0 { + continue + } + mv = append(mv, &ModVulns{ + Module: modules[i], + Vulns: resp.Entries, + }) + } + return mv, nil +} diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/packages.go b/vendor/golang.org/x/vuln/internal/vulncheck/packages.go new file mode 100644 index 000000000..df989e70a --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/packages.go @@ -0,0 +1,194 @@ +// Copyright 2023 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 vulncheck + +import ( + "fmt" + "strings" + + "golang.org/x/tools/go/packages" + "golang.org/x/vuln/internal" + "golang.org/x/vuln/internal/semver" +) + +// PackageGraph holds a complete module and package graph. +// Its primary purpose is to allow fast access to the nodes by path. +type PackageGraph struct { + modules map[string]*packages.Module + packages map[string]*packages.Package +} + +func NewPackageGraph(goVersion string) *PackageGraph { + graph := &PackageGraph{ + modules: map[string]*packages.Module{}, + packages: map[string]*packages.Package{}, + } + graph.AddModules(&packages.Module{ + Path: internal.GoStdModulePath, + Version: semver.GoTagToSemver(goVersion), + }) + return graph +} + +// AddModules adds the modules and any replace modules provided. +// It will ignore modules that have duplicate paths to ones the graph already holds. +func (g *PackageGraph) AddModules(mods ...*packages.Module) { + for _, mod := range mods { + if _, found := g.modules[mod.Path]; found { + //TODO: check duplicates are okay? + continue + } + g.modules[mod.Path] = mod + if mod.Replace != nil { + g.AddModules(mod.Replace) + } + } +} + +// . +func (g *PackageGraph) GetModule(path string) *packages.Module { + if mod, ok := g.modules[path]; ok { + return mod + } + mod := &packages.Module{ + Path: path, + Version: "", + } + g.AddModules(mod) + return mod +} + +// AddPackages adds the packages and the full graph of imported packages. +// It will ignore packages that have duplicate paths to ones the graph already holds. +func (g *PackageGraph) AddPackages(pkgs ...*packages.Package) { + for _, pkg := range pkgs { + if _, found := g.packages[pkg.PkgPath]; found { + //TODO: check duplicates are okay? + continue + } + g.packages[pkg.PkgPath] = pkg + g.fixupPackage(pkg) + for _, child := range pkg.Imports { + g.AddPackages(child) + } + } +} + +func (g *PackageGraph) fixupPackage(pkg *packages.Package) { + if pkg.Module != nil { + g.AddModules(pkg.Module) + return + } + pkg.Module = g.findModule(pkg.PkgPath) +} + +// findModule finds a module for package. +// It does a longest prefix search amongst the existing modules, if that does +// not find anything, it returns the "unknown" module. +func (g *PackageGraph) findModule(pkgPath string) *packages.Module { + //TODO: better stdlib test + if !strings.Contains(pkgPath, ".") { + return g.GetModule(internal.GoStdModulePath) + } + for _, m := range g.modules { + //TODO: not first match, best match... + if pkgPath == m.Path || strings.HasPrefix(pkgPath, m.Path+"/") { + return m + } + } + return g.GetModule(internal.UnknownModulePath) +} + +// GetPackage returns the package matching the path. +// If the graph does not already know about the package, a new one is added. +func (g *PackageGraph) GetPackage(path string) *packages.Package { + if pkg, ok := g.packages[path]; ok { + return pkg + } + pkg := &packages.Package{ + PkgPath: path, + } + g.AddPackages(pkg) + return pkg +} + +// LoadPackages loads the packages specified by the patterns into the graph. +// See golang.org/x/tools/go/packages.Load for details of how it works. +func (g *PackageGraph) LoadPackagesAndMods(cfg *packages.Config, tags []string, patterns []string) ([]*packages.Package, []*packages.Module, error) { + if len(tags) > 0 { + cfg.BuildFlags = []string{fmt.Sprintf("-tags=%s", strings.Join(tags, ","))} + } + cfg.Mode |= + packages.NeedDeps | + packages.NeedImports | + packages.NeedModule | + packages.NeedSyntax | + packages.NeedTypes | + packages.NeedTypesInfo | + packages.NeedName + + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + return nil, nil, err + } + var perrs []packages.Error + packages.Visit(pkgs, nil, func(p *packages.Package) { + perrs = append(perrs, p.Errors...) + }) + if len(perrs) > 0 { + err = &packageError{perrs} + } + g.AddPackages(pkgs...) + return pkgs, extractModules(pkgs), err +} + +// extractModules collects modules in `pkgs` up to uniqueness of +// module path and version. +func extractModules(pkgs []*packages.Package) []*packages.Module { + modMap := map[string]*packages.Module{} + seen := map[*packages.Package]bool{} + var extract func(*packages.Package, map[string]*packages.Module) + extract = func(pkg *packages.Package, modMap map[string]*packages.Module) { + if pkg == nil || seen[pkg] { + return + } + if pkg.Module != nil { + if pkg.Module.Replace != nil { + modMap[pkg.Module.Replace.Path] = pkg.Module + } else { + modMap[pkg.Module.Path] = pkg.Module + } + } + seen[pkg] = true + for _, imp := range pkg.Imports { + extract(imp, modMap) + } + } + for _, pkg := range pkgs { + extract(pkg, modMap) + } + + modules := []*packages.Module{} + for _, mod := range modMap { + modules = append(modules, mod) + } + return modules +} + +// packageError contains errors from loading a set of packages. +type packageError struct { + Errors []packages.Error +} + +func (e *packageError) Error() string { + var b strings.Builder + fmt.Fprintln(&b, "\nThere are errors with the provided package patterns:") + fmt.Fprintln(&b, "") + for _, e := range e.Errors { + fmt.Fprintln(&b, e) + } + fmt.Fprintln(&b, "\nFor details on package patterns, see https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns.") + return b.String() +} diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/slicing.go b/vendor/golang.org/x/vuln/internal/vulncheck/slicing.go new file mode 100644 index 000000000..71fffc416 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/slicing.go @@ -0,0 +1,55 @@ +// Copyright 2021 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 vulncheck + +import ( + "golang.org/x/tools/go/callgraph" + "golang.org/x/tools/go/ssa" +) + +// forwardSlice computes the transitive closure of functions forward reachable +// via calls in cg or referred to in an instruction starting from `sources`. +func forwardSlice(sources map[*ssa.Function]bool, cg *callgraph.Graph) map[*ssa.Function]bool { + seen := make(map[*ssa.Function]bool) + var visit func(f *ssa.Function) + visit = func(f *ssa.Function) { + if seen[f] { + return + } + seen[f] = true + + if n := cg.Nodes[f]; n != nil { + for _, e := range n.Out { + if e.Site != nil { + visit(e.Callee.Func) + } + } + } + + var buf [10]*ssa.Value // avoid alloc in common case + for _, b := range f.Blocks { + for _, instr := range b.Instrs { + for _, op := range instr.Operands(buf[:0]) { + if fn, ok := (*op).(*ssa.Function); ok { + visit(fn) + } + } + } + } + } + for source := range sources { + visit(source) + } + return seen +} + +// pruneSet removes functions in `set` that are in `toPrune`. +func pruneSet(set, toPrune map[*ssa.Function]bool) { + for f := range set { + if !toPrune[f] { + delete(set, f) + } + } +} diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/source.go b/vendor/golang.org/x/vuln/internal/vulncheck/source.go new file mode 100644 index 000000000..da1c31338 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/source.go @@ -0,0 +1,308 @@ +// Copyright 2021 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 vulncheck + +import ( + "context" + "sync" + + "golang.org/x/tools/go/callgraph" + "golang.org/x/tools/go/packages" + "golang.org/x/tools/go/ssa" + "golang.org/x/vuln/internal/client" + "golang.org/x/vuln/internal/govulncheck" + "golang.org/x/vuln/internal/osv" +) + +// Source detects vulnerabilities in pkgs and emits the findings to handler. +func Source(ctx context.Context, handler govulncheck.Handler, pkgs []*packages.Package, mods []*packages.Module, cfg *govulncheck.Config, client *client.Client, graph *PackageGraph) error { + vr, err := source(ctx, handler, pkgs, mods, cfg, client, graph) + if err != nil { + return err + } + + if cfg.ScanLevel.WantSymbols() { + return emitCallFindings(handler, sourceCallstacks(vr)) + } + return nil +} + +// source detects vulnerabilities in packages. It emits findings to handler +// and produces a Result that contains info on detected vulnerabilities. +// +// Assumes that pkgs are non-empty and belong to the same program. +func source(ctx context.Context, handler govulncheck.Handler, pkgs []*packages.Package, mods []*packages.Module, cfg *govulncheck.Config, client *client.Client, graph *PackageGraph) (*Result, error) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // If we are building the callgraph, build ssa and the callgraph in parallel + // with fetching vulnerabilities. If the vulns set is empty, return without + // waiting for SSA construction or callgraph to finish. + var ( + wg sync.WaitGroup // guards entries, cg, and buildErr + entries []*ssa.Function + cg *callgraph.Graph + buildErr error + ) + if cfg.ScanLevel.WantSymbols() { + fset := pkgs[0].Fset + wg.Add(1) + go func() { + defer wg.Done() + prog, ssaPkgs := buildSSA(pkgs, fset) + entries = entryPoints(ssaPkgs) + cg, buildErr = callGraph(ctx, prog, entries) + }() + } + + mv, err := FetchVulnerabilities(ctx, client, mods) + if err != nil { + return nil, err + } + + // Emit OSV entries immediately in their raw unfiltered form. + if err := emitOSVs(handler, mv); err != nil { + return nil, err + } + + affVulns := affectingVulnerabilities(mv, "", "") + if err := emitModuleFindings(handler, affVulns); err != nil { + return nil, err + } + + if !cfg.ScanLevel.WantPackages() || len(affVulns) == 0 { + return &Result{}, nil + } + + impVulns := importedVulnPackages(pkgs, affVulns) + // Emit information on imported vulnerable packages now as + // call graph computation might take a while. + if err := emitPackageFindings(handler, impVulns); err != nil { + return nil, err + } + + // Return result immediately if not in symbol mode or + // if there are no vulnerabilities imported. + if !cfg.ScanLevel.WantSymbols() || len(impVulns) == 0 { + return &Result{Vulns: impVulns}, nil + } + + wg.Wait() // wait for build to finish + if buildErr != nil { + return nil, err + } + + entryFuncs, callVulns := calledVulnSymbols(entries, affVulns, cg, graph) + return &Result{EntryFunctions: entryFuncs, Vulns: callVulns}, nil +} + +// importedVulnPackages detects imported vulnerable packages. +func importedVulnPackages(pkgs []*packages.Package, affVulns affectingVulns) []*Vuln { + var vulns []*Vuln + analyzed := make(map[*packages.Package]bool) // skip analyzing the same package multiple times + var vulnImports func(pkg *packages.Package) + vulnImports = func(pkg *packages.Package) { + if analyzed[pkg] { + return + } + + osvs := affVulns.ForPackage(pkg.PkgPath) + // Create Vuln entry for each OSV entry for pkg. + for _, osv := range osvs { + vuln := &Vuln{ + OSV: osv, + Package: pkg, + } + vulns = append(vulns, vuln) + } + + analyzed[pkg] = true + for _, imp := range pkg.Imports { + vulnImports(imp) + } + } + + for _, pkg := range pkgs { + vulnImports(pkg) + } + return vulns +} + +// calledVulnSymbols detects vuln symbols transitively reachable from sources +// via call graph cg. +// +// A slice of call graph is computed related to the reachable vulnerabilities. Each +// reachable Vuln has attached FuncNode that can be upward traversed to the entry points. +// Entry points that reach the vulnerable symbols are also returned. +func calledVulnSymbols(sources []*ssa.Function, affVulns affectingVulns, cg *callgraph.Graph, graph *PackageGraph) ([]*FuncNode, []*Vuln) { + sinksWithVulns := vulnFuncs(cg, affVulns) + + // Compute call graph backwards reachable + // from vulnerable functions and methods. + var sinks []*callgraph.Node + for n := range sinksWithVulns { + sinks = append(sinks, n) + } + bcg := callGraphSlice(sinks, false) + + // Interesect backwards call graph with forward + // reachable graph to remove redundant edges. + var filteredSources []*callgraph.Node + for _, e := range sources { + if n, ok := bcg.Nodes[e]; ok { + filteredSources = append(filteredSources, n) + } + } + fcg := callGraphSlice(filteredSources, true) + + // Get the sinks that are in fact reachable from entry points. + filteredSinks := make(map[*callgraph.Node][]*osv.Entry) + for n, vs := range sinksWithVulns { + if fn, ok := fcg.Nodes[n.Func]; ok { + filteredSinks[fn] = vs + } + } + + // Transform the resulting call graph slice into + // vulncheck representation. + return vulnCallGraph(filteredSources, filteredSinks, graph) +} + +// callGraphSlice computes a slice of callgraph beginning at starts +// in the direction (forward/backward) controlled by forward flag. +func callGraphSlice(starts []*callgraph.Node, forward bool) *callgraph.Graph { + g := &callgraph.Graph{Nodes: make(map[*ssa.Function]*callgraph.Node)} + + visited := make(map[*callgraph.Node]bool) + var visit func(*callgraph.Node) + visit = func(n *callgraph.Node) { + if visited[n] { + return + } + visited[n] = true + + var edges []*callgraph.Edge + if forward { + edges = n.Out + } else { + edges = n.In + } + + for _, edge := range edges { + nCallee := g.CreateNode(edge.Callee.Func) + nCaller := g.CreateNode(edge.Caller.Func) + callgraph.AddEdge(nCaller, edge.Site, nCallee) + + if forward { + visit(edge.Callee) + } else { + visit(edge.Caller) + } + } + } + + for _, s := range starts { + visit(s) + } + return g +} + +// vulnCallGraph creates vulnerability call graph in terms of sources and sinks. +func vulnCallGraph(sources []*callgraph.Node, sinks map[*callgraph.Node][]*osv.Entry, graph *PackageGraph) ([]*FuncNode, []*Vuln) { + var entries []*FuncNode + var vulns []*Vuln + nodes := make(map[*ssa.Function]*FuncNode) + + // First create entries and sinks and store relevant information. + for _, s := range sources { + fn := createNode(nodes, s.Func, graph) + entries = append(entries, fn) + } + + for s, osvs := range sinks { + f := s.Func + funNode := createNode(nodes, s.Func, graph) + + // Populate CallSink field for each detected vuln symbol. + for _, osv := range osvs { + vulns = append(vulns, calledVuln(funNode, osv, dbFuncName(f), funNode.Package)) + } + } + + visited := make(map[*callgraph.Node]bool) + var visit func(*callgraph.Node) + visit = func(n *callgraph.Node) { + if visited[n] { + return + } + visited[n] = true + + for _, edge := range n.In { + nCallee := createNode(nodes, edge.Callee.Func, graph) + nCaller := createNode(nodes, edge.Caller.Func, graph) + + call := edge.Site + cs := &CallSite{ + Parent: nCaller, + Name: call.Common().Value.Name(), + RecvType: callRecvType(call), + Resolved: resolved(call), + Pos: instrPosition(call), + } + nCallee.CallSites = append(nCallee.CallSites, cs) + + visit(edge.Caller) + } + } + + for s := range sinks { + visit(s) + } + return entries, vulns +} + +// vulnFuncs returns vulnerability information for vulnerable functions in cg. +func vulnFuncs(cg *callgraph.Graph, affVulns affectingVulns) map[*callgraph.Node][]*osv.Entry { + m := make(map[*callgraph.Node][]*osv.Entry) + for f, n := range cg.Nodes { + vulns := affVulns.ForSymbol(pkgPath(f), dbFuncName(f)) + if len(vulns) > 0 { + m[n] = vulns + } + } + return m +} + +// pkgPath returns the path of the f's enclosing package, if any. +// Otherwise, returns "". +func pkgPath(f *ssa.Function) string { + if f.Package() != nil && f.Package().Pkg != nil { + return f.Package().Pkg.Path() + } + return "" +} + +func createNode(nodes map[*ssa.Function]*FuncNode, f *ssa.Function, graph *PackageGraph) *FuncNode { + if fn, ok := nodes[f]; ok { + return fn + } + fn := &FuncNode{ + Name: f.Name(), + Package: graph.GetPackage(pkgPath(f)), + RecvType: funcRecvType(f), + Pos: funcPosition(f), + } + nodes[f] = fn + return fn +} + +func calledVuln(call *FuncNode, osv *osv.Entry, symbol string, pkg *packages.Package) *Vuln { + return &Vuln{ + Symbol: symbol, + Package: pkg, + OSV: osv, + CallSink: call, + } +} diff --git a/vendor/golang.org/x/vuln/vulncheck/utils.go b/vendor/golang.org/x/vuln/internal/vulncheck/utils.go similarity index 58% rename from vendor/golang.org/x/vuln/vulncheck/utils.go rename to vendor/golang.org/x/vuln/internal/vulncheck/utils.go index 878b76c5b..9cf30da30 100644 --- a/vendor/golang.org/x/vuln/vulncheck/utils.go +++ b/vendor/golang.org/x/vuln/internal/vulncheck/utils.go @@ -6,16 +6,20 @@ package vulncheck import ( "bytes" + "context" "go/token" "go/types" + "sort" "strings" "golang.org/x/tools/go/callgraph" "golang.org/x/tools/go/callgraph/cha" "golang.org/x/tools/go/callgraph/vta" + "golang.org/x/tools/go/packages" "golang.org/x/tools/go/ssa/ssautil" "golang.org/x/tools/go/types/typeutil" - "golang.org/x/vuln/osv" + "golang.org/x/vuln/internal/osv" + "golang.org/x/vuln/internal/semver" "golang.org/x/tools/go/ssa" ) @@ -23,15 +27,15 @@ import ( // buildSSA creates an ssa representation for pkgs. Returns // the ssa program encapsulating the packages and top level // ssa packages corresponding to pkgs. -func buildSSA(pkgs []*Package, fset *token.FileSet) (*ssa.Program, []*ssa.Package) { - prog := ssa.NewProgram(fset, ssa.BuilderMode(0)) +func buildSSA(pkgs []*packages.Package, fset *token.FileSet) (*ssa.Program, []*ssa.Package) { + prog := ssa.NewProgram(fset, ssa.InstantiateGenerics) - imports := make(map[*Package]*ssa.Package) - var createImports func([]*Package) - createImports = func(pkgs []*Package) { + imports := make(map[*packages.Package]*ssa.Package) + var createImports func(map[string]*packages.Package) + createImports = func(pkgs map[string]*packages.Package) { for _, p := range pkgs { if _, ok := imports[p]; !ok { - i := prog.CreatePackage(p.Pkg, p.Syntax, p.TypesInfo, true) + i := prog.CreatePackage(p.Types, p.Syntax, p.TypesInfo, true) imports[p] = i createImports(p.Imports) } @@ -47,7 +51,7 @@ func buildSSA(pkgs []*Package, fset *token.FileSet) (*ssa.Program, []*ssa.Packag if sp, ok := imports[tp]; ok { ssaPkgs = append(ssaPkgs, sp) } else { - sp := prog.CreatePackage(tp.Pkg, tp.Syntax, tp.TypesInfo, false) + sp := prog.CreatePackage(tp.Types, tp.Syntax, tp.TypesInfo, false) ssaPkgs = append(ssaPkgs, sp) } } @@ -56,46 +60,38 @@ func buildSSA(pkgs []*Package, fset *token.FileSet) (*ssa.Program, []*ssa.Packag } // callGraph builds a call graph of prog based on VTA analysis. -func callGraph(prog *ssa.Program, entries []*ssa.Function) *callgraph.Graph { +func callGraph(ctx context.Context, prog *ssa.Program, entries []*ssa.Function) (*callgraph.Graph, error) { entrySlice := make(map[*ssa.Function]bool) for _, e := range entries { entrySlice[e] = true } + + if err := ctx.Err(); err != nil { // cancelled? + return nil, err + } initial := cha.CallGraph(prog) allFuncs := ssautil.AllFunctions(prog) - fslice := forwardReachableFrom(entrySlice, initial) + fslice := forwardSlice(entrySlice, initial) // Keep only actually linked functions. pruneSet(fslice, allFuncs) + + if err := ctx.Err(); err != nil { // cancelled? + return nil, err + } vtaCg := vta.CallGraph(fslice, initial) // Repeat the process once more, this time using // the produced VTA call graph as the base graph. - fslice = forwardReachableFrom(entrySlice, vtaCg) + fslice = forwardSlice(entrySlice, vtaCg) pruneSet(fslice, allFuncs) + if err := ctx.Err(); err != nil { // cancelled? + return nil, err + } cg := vta.CallGraph(fslice, vtaCg) cg.DeleteSyntheticNodes() - return cg -} - -// siteCallees computes a set of callees for call site `call` given program `callgraph`. -func siteCallees(call ssa.CallInstruction, callgraph *callgraph.Graph) []*ssa.Function { - var matches []*ssa.Function - - node := callgraph.Nodes[call.Parent()] - if node == nil { - return nil - } - - for _, edge := range node.Out { - // Some callgraph analyses, such as CHA, might return synthetic (interface) - // methods as well as the concrete methods. Skip such synthetic functions. - if edge.Site == call { - matches = append(matches, edge.Callee.Func) - } - } - return matches + return cg, nil } // dbTypeFormat formats the name of t according how types @@ -115,15 +111,17 @@ func dbTypeFormat(t types.Type) string { // dbFuncName computes a function name consistent with the namings used in vulnerability // databases. Effectively, a qualified name of a function local to its enclosing package. -// If a receiver is a pointer, this information is not encoded in the resulting name. The -// name of anonymous functions is simply "". The function names are unique subject to the -// enclosing package, but not globally. +// If a receiver is a pointer, this information is not encoded in the resulting name. If +// a function has type argument/parameter, this information is omitted. The name of +// anonymous functions is simply "". The function names are unique subject to the enclosing +// package, but not globally. // // Examples: // // func (a A) foo (...) {...} -> A.foo // func foo(...) {...} -> foo // func (b *B) bar (...) {...} -> B.bar +// func (c C[T]) do(...) {...} -> C.do func dbFuncName(f *ssa.Function) string { selectBound := func(f *ssa.Function) types.Type { // If f is a "bound" function introduced by ssa for a given type, return the type. @@ -156,18 +154,17 @@ func dbFuncName(f *ssa.Function) string { } if qprefix == "" { - return f.Name() + return funcName(f) } - return qprefix + "." + f.Name() + return qprefix + "." + funcName(f) } -// dbTypesFuncName is dbFuncName defined over *types.Func. -func dbTypesFuncName(f *types.Func) string { - sig := f.Type().(*types.Signature) - if sig.Recv() == nil { - return f.Name() - } - return dbTypeFormat(sig.Recv().Type()) + "." + f.Name() +// funcName returns the name of the ssa function f. +// It is f.Name() without additional type argument +// information in case of generics. +func funcName(f *ssa.Function) string { + n, _, _ := strings.Cut(f.Name(), "[") + return n } // memberFuncs returns functions associated with the `member`: @@ -232,35 +229,89 @@ func funcRecvType(f *ssa.Function) string { return buf.String() } -// allSymbols returns all top-level functions and methods defined in pkg. -func allSymbols(pkg *types.Package) []string { - var names []string - scope := pkg.Scope() - for _, name := range scope.Names() { - o := scope.Lookup(name) - switch o := o.(type) { - case *types.Func: - names = append(names, dbTypesFuncName(o)) - case *types.TypeName: - ms := types.NewMethodSet(types.NewPointer(o.Type())) - for i := 0; i < ms.Len(); i++ { - if f, ok := ms.At(i).Obj().(*types.Func); ok { - names = append(names, dbTypesFuncName(f)) +func FixedVersion(modulePath, version string, affected []osv.Affected) string { + fixed := earliestValidFix(modulePath, version, affected) + // Add "v" prefix if one does not exist. moduleVersionString + // will later on replace it with "go" if needed. + if fixed != "" && !strings.HasPrefix(fixed, "v") { + fixed = "v" + fixed + } + return fixed +} + +// earliestValidFix returns the earliest fix for version of modulePath that +// itself is not vulnerable in affected. +// +// Suppose we have a version "v1.0.0" and we use {...} to denote different +// affected regions. Assume for simplicity that all affected apply to the +// same input modulePath. +// +// {[v0.1.0, v0.1.9), [v1.0.0, v2.0.0)} -> v2.0.0 +// {[v1.0.0, v1.5.0), [v2.0.0, v2.1.0}, {[v1.4.0, v1.6.0)} -> v2.1.0 +func earliestValidFix(modulePath, version string, affected []osv.Affected) string { + var moduleAffected []osv.Affected + for _, a := range affected { + if a.Module.Path == modulePath { + moduleAffected = append(moduleAffected, a) + } + } + + vFixes := validFixes(version, moduleAffected) + for _, fix := range vFixes { + if !fixNegated(fix, moduleAffected) { + return fix + } + } + return "" + +} + +// validFixes computes all fixes for version in affected and +// returns them sorted increasingly. Assumes that all affected +// apply to the same module. +func validFixes(version string, affected []osv.Affected) []string { + var fixes []string + for _, a := range affected { + for _, r := range a.Ranges { + if r.Type != osv.RangeTypeSemver { + continue + } + for _, e := range r.Events { + fix := e.Fixed + if fix != "" && semver.Less(version, fix) { + fixes = append(fixes, fix) } } } } - return names + sort.SliceStable(fixes, func(i, j int) bool { return semver.Less(fixes[i], fixes[j]) }) + return fixes } -// vulnMatchesPackage reports whether an entry applies to pkg (an import path). -func vulnMatchesPackage(v *osv.Entry, pkg string) bool { - for _, a := range v.Affected { - for _, p := range a.EcosystemSpecific.Imports { - if p.Path == pkg { +// fixNegated checks if fix is negated to by a re-introduction +// of a vulnerability in affected. Assumes that all affected apply +// to the same module. +func fixNegated(fix string, affected []osv.Affected) bool { + for _, a := range affected { + for _, r := range a.Ranges { + if semver.ContainsSemver(r, fix) { return true } } } return false } + +func modPath(mod *packages.Module) string { + if mod.Replace != nil { + return mod.Replace.Path + } + return mod.Path +} + +func modVersion(mod *packages.Module) string { + if mod.Replace != nil { + return mod.Replace.Version + } + return mod.Version +} diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/vulncheck.go b/vendor/golang.org/x/vuln/internal/vulncheck/vulncheck.go new file mode 100644 index 000000000..6b8309ae7 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/vulncheck.go @@ -0,0 +1,312 @@ +// Copyright 2021 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 vulncheck + +import ( + "fmt" + "go/token" + "strings" + "time" + + "golang.org/x/tools/go/packages" + "golang.org/x/vuln/internal" + "golang.org/x/vuln/internal/osv" + "golang.org/x/vuln/internal/semver" +) + +// Result contains information on detected vulnerabilities. +// For call graph analysis, it provides information on reachability +// of vulnerable symbols through entry points of the program. +type Result struct { + // EntryFunctions are a subset of Functions representing vulncheck entry points. + EntryFunctions []*FuncNode + + // Vulns contains information on detected vulnerabilities. + Vulns []*Vuln +} + +// Vuln provides information on a detected vulnerability. For call +// graph mode, Vuln will also contain the information on how the +// vulnerability is reachable in the user call graph. +type Vuln struct { + // OSV contains information on the detected vulnerability in the shared + // vulnerability format. + // + // OSV, Symbol, and Package identify a vulnerability. + // + // Note that *osv.Entry may describe multiple symbols from multiple + // packages. + OSV *osv.Entry + + // Symbol is the name of the detected vulnerable function or method. + Symbol string + + // CallSink is the FuncNode corresponding to Symbol. + // + // When analyzing binaries, Symbol is not reachable, or cfg.ScanLevel + // is symbol, CallSink will be unavailable and set to nil. + CallSink *FuncNode + + // Package of Symbol. + // + // When the package of symbol is not imported, Package will be + // unavailable and set to nil. + Package *packages.Package +} + +// A FuncNode describes a function in the call graph. +type FuncNode struct { + // Name is the name of the function. + Name string + + // RecvType is the receiver object type of this function, if any. + RecvType string + + // Package is the package the function is part of. + Package *packages.Package + + // Position describes the position of the function in the file. + Pos *token.Position + + // CallSites is a set of call sites where this function is called. + CallSites []*CallSite +} + +func (fn *FuncNode) String() string { + if fn.RecvType == "" { + return fmt.Sprintf("%s.%s", fn.Package.PkgPath, fn.Name) + } + return fmt.Sprintf("%s.%s", fn.RecvType, fn.Name) +} + +// Receiver returns the FuncNode's receiver, with package path removed. +// Pointers are preserved if present. +func (fn *FuncNode) Receiver() string { + return strings.Replace(fn.RecvType, fmt.Sprintf("%s.", fn.Package.PkgPath), "", 1) +} + +// A CallSite describes a function call. +type CallSite struct { + // Parent is the enclosing function where the call is made. + Parent *FuncNode + + // Name stands for the name of the function (variable) being called. + Name string + + // RecvType is the full path of the receiver object type, if any. + RecvType string + + // Position describes the position of the function in the file. + Pos *token.Position + + // Resolved indicates if the called function can be statically resolved. + Resolved bool +} + +// affectingVulns is an internal structure for querying +// vulnerabilities that apply to the current program +// and platform under consideration. +type affectingVulns []*ModVulns + +// ModVulns groups vulnerabilities per module. +type ModVulns struct { + Module *packages.Module + Vulns []*osv.Entry +} + +func affectingVulnerabilities(vulns []*ModVulns, os, arch string) affectingVulns { + now := time.Now() + var filtered affectingVulns + for _, mod := range vulns { + module := mod.Module + modVersion := module.Version + if module.Replace != nil { + modVersion = module.Replace.Version + } + // TODO(https://golang.org/issues/49264): if modVersion == "", try vcs? + var filteredVulns []*osv.Entry + for _, v := range mod.Vulns { + // Ignore vulnerabilities that have been withdrawn + if v.Withdrawn != nil && v.Withdrawn.Before(now) { + continue + } + + var filteredAffected []osv.Affected + for _, a := range v.Affected { + // Vulnerabilities from some databases might contain + // information on related but different modules that + // were, say, reported in the same CVE. We filter such + // information out as it might lead to incorrect results: + // Computing a latest fix could consider versions of these + // different packages. + if a.Module.Path != module.Path { + continue + } + + // A module version is affected if + // - it is included in one of the affected version ranges + // - and module version is not "" + if modVersion == "" { + // Module version of "" means the module version is not available, + // and so we don't want to spam users with potential false alarms. + continue + } + if !semver.Affects(a.Ranges, modVersion) { + continue + } + var filteredImports []osv.Package + for _, p := range a.EcosystemSpecific.Packages { + if matchesPlatform(os, arch, p) { + filteredImports = append(filteredImports, p) + } + } + // If we pruned all existing Packages, then the affected is + // empty and we can filter it out. Note that Packages can + // be empty for vulnerabilities that have no package or + // symbol information available. + if len(a.EcosystemSpecific.Packages) != 0 && len(filteredImports) == 0 { + continue + } + a.EcosystemSpecific.Packages = filteredImports + filteredAffected = append(filteredAffected, a) + } + if len(filteredAffected) == 0 { + continue + } + // save the non-empty vulnerability with only + // affected symbols. + newV := *v + newV.Affected = filteredAffected + filteredVulns = append(filteredVulns, &newV) + } + + filtered = append(filtered, &ModVulns{ + Module: module, + Vulns: filteredVulns, + }) + } + return filtered +} + +func matchesPlatform(os, arch string, e osv.Package) bool { + return matchesPlatformComponent(os, e.GOOS) && + matchesPlatformComponent(arch, e.GOARCH) +} + +// matchesPlatformComponent reports whether a GOOS (or GOARCH) +// matches a list of GOOS (or GOARCH) values from an osv.EcosystemSpecificImport. +func matchesPlatformComponent(s string, ps []string) bool { + // An empty input or an empty GOOS or GOARCH list means "matches everything." + if s == "" || len(ps) == 0 { + return true + } + for _, p := range ps { + if s == p { + return true + } + } + return false +} + +// ForPackage returns the vulnerabilities for the module which is the most +// specific prefix of importPath, or nil if there is no matching module with +// vulnerabilities. +func (aff affectingVulns) ForPackage(importPath string) []*osv.Entry { + isStd := IsStdPackage(importPath) + var mostSpecificMod *ModVulns + for _, mod := range aff { + md := mod + if isStd && mod.Module.Path == internal.GoStdModulePath { + // standard library packages do not have an associated module, + // so we relate them to the artificial stdlib module. + mostSpecificMod = md + } else if strings.HasPrefix(importPath, md.Module.Path) { + if mostSpecificMod == nil || len(mostSpecificMod.Module.Path) < len(md.Module.Path) { + mostSpecificMod = md + } + } + } + if mostSpecificMod == nil { + return nil + } + + if mostSpecificMod.Module.Replace != nil { + // standard libraries do not have a module nor replace module + importPath = fmt.Sprintf("%s%s", mostSpecificMod.Module.Replace.Path, strings.TrimPrefix(importPath, mostSpecificMod.Module.Path)) + } + vulns := mostSpecificMod.Vulns + packageVulns := []*osv.Entry{} +Vuln: + for _, v := range vulns { + for _, a := range v.Affected { + if len(a.EcosystemSpecific.Packages) == 0 { + // no packages means all packages are vulnerable + packageVulns = append(packageVulns, v) + continue Vuln + } + + for _, p := range a.EcosystemSpecific.Packages { + if p.Path == importPath { + packageVulns = append(packageVulns, v) + continue Vuln + } + } + } + } + return packageVulns +} + +// ForSymbol returns vulnerabilities for symbol in aff.ForPackage(importPath). +func (aff affectingVulns) ForSymbol(importPath, symbol string) []*osv.Entry { + vulns := aff.ForPackage(importPath) + if vulns == nil { + return nil + } + + symbolVulns := []*osv.Entry{} +vulnLoop: + for _, v := range vulns { + for _, a := range v.Affected { + if len(a.EcosystemSpecific.Packages) == 0 { + // no packages means all symbols of all packages are vulnerable + symbolVulns = append(symbolVulns, v) + continue vulnLoop + } + + for _, p := range a.EcosystemSpecific.Packages { + if p.Path != importPath { + continue + } + if len(p.Symbols) > 0 && !contains(p.Symbols, symbol) { + continue + } + symbolVulns = append(symbolVulns, v) + continue vulnLoop + } + } + } + return symbolVulns +} + +func contains(symbols []string, target string) bool { + for _, s := range symbols { + if s == target { + return true + } + } + return false +} + +func IsStdPackage(pkg string) bool { + if pkg == "" { + return false + } + // std packages do not have a "." in their path. For instance, see + // Contains in pkgsite/+/refs/heads/master/internal/stdlbib/stdlib.go. + if i := strings.IndexByte(pkg, '/'); i != -1 { + pkg = pkg[:i] + } + return !strings.Contains(pkg, ".") +} diff --git a/vendor/golang.org/x/vuln/internal/vulncheck/witness.go b/vendor/golang.org/x/vuln/internal/vulncheck/witness.go new file mode 100644 index 000000000..ff87668c9 --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/vulncheck/witness.go @@ -0,0 +1,447 @@ +// Copyright 2021 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 vulncheck + +import ( + "container/list" + "fmt" + "go/ast" + "go/token" + "sort" + "strconv" + "strings" + "sync" + "unicode" + + "golang.org/x/tools/go/packages" +) + +// CallStack is a call stack starting with a client +// function or method and ending with a call to a +// vulnerable symbol. +type CallStack []StackEntry + +// StackEntry is an element of a call stack. +type StackEntry struct { + // Function whose frame is on the stack. + Function *FuncNode + + // Call is the call site inducing the next stack frame. + // nil when the frame represents the last frame in the stack. + Call *CallSite +} + +// sourceCallstacks returns representative call stacks for each +// vulnerability in res. The returned call stacks are heuristically +// ordered by how seemingly easy is to understand them: shorter +// call stacks with less dynamic call sites appear earlier in the +// returned slices. +// +// sourceCallstacks performs a breadth-first search of res.CallGraph +// starting at the vulnerable symbol and going up until reaching an entry +// function or method in res.CallGraph.Entries. During this search, +// each function is visited at most once to avoid potential +// exponential explosion. Hence, not all call stacks are analyzed. +func sourceCallstacks(res *Result) map[*Vuln]CallStack { + var ( + wg sync.WaitGroup + mu sync.Mutex + ) + stackPerVuln := make(map[*Vuln]CallStack) + for _, vuln := range res.Vulns { + vuln := vuln + wg.Add(1) + go func() { + cs := sourceCallstack(vuln, res) + mu.Lock() + stackPerVuln[vuln] = cs + mu.Unlock() + wg.Done() + }() + } + wg.Wait() + + updateInitPositions(stackPerVuln) + return stackPerVuln +} + +// sourceCallstack finds a representative call stack for vuln. +// This is a shortest unique call stack with the least +// number of dynamic call sites. +func sourceCallstack(vuln *Vuln, res *Result) CallStack { + vulnSink := vuln.CallSink + if vulnSink == nil { + return nil + } + + entries := make(map[*FuncNode]bool) + for _, e := range res.EntryFunctions { + entries[e] = true + } + + seen := make(map[*FuncNode]bool) + + // Do a BFS from the vuln sink to the entry points + // and find the representative call stack. This is + // the shortest call stack that goes through the + // least number of dynamic call sites. We first + // collect all candidate call stacks of the shortest + // length and then pick the best one accordingly. + var candidates []CallStack + candDepth := 0 + queue := list.New() + queue.PushBack(&callChain{f: vulnSink}) + + // We want to avoid call stacks that go through + // other vulnerable symbols of the same package + // for the same vulnerability. In other words, + // we want unique call stacks. + skipSymbols := make(map[*FuncNode]bool) + for _, v := range res.Vulns { + if v.CallSink != nil && v != vuln && + v.OSV == vuln.OSV && v.Package == vuln.Package { + skipSymbols[v.CallSink] = true + } + } + + for queue.Len() > 0 { + front := queue.Front() + c := front.Value.(*callChain) + queue.Remove(front) + + f := c.f + if seen[f] { + continue + } + seen[f] = true + + // Pick a single call site for each function in determinstic order. + // A single call site is sufficient as we visit a function only once. + for _, cs := range callsites(f.CallSites, seen) { + nStack := &callChain{f: cs.Parent, call: cs, child: c} + if !skipSymbols[cs.Parent] { + queue.PushBack(nStack) + } + + if entries[cs.Parent] { + ns := nStack.CallStack() + if len(candidates) == 0 || len(ns) == candDepth { + // The case where we either have not identified + // any call stacks or just found one of the same + // length as the previous ones. + candidates = append(candidates, ns) + candDepth = len(ns) + } else { + // We just found a candidate call stack whose + // length is greater than what we previously + // found. We can thus safely disregard this + // call stack and stop searching since we won't + // be able to find any better candidates. + queue.Init() // clear the list, effectively exiting the outer loop + } + } + } + } + + // Sort candidate call stacks by their number of dynamic call + // sites and return the first one. + sort.SliceStable(candidates, func(i int, j int) bool { + s1, s2 := candidates[i], candidates[j] + if w1, w2 := weight(s1), weight(s2); w1 != w2 { + return w1 < w2 + } + + // At this point, the stableness/determinism of + // sorting is guaranteed by the determinism of + // the underlying call graph and the call stack + // search algorithm. + return true + }) + if len(candidates) == 0 { + return nil + } + return candidates[0] +} + +// callsites picks a call site from sites for each non-visited function. +// For each such function, the smallest (posLess) call site is chosen. The +// returned slice is sorted by caller functions (funcLess). Assumes callee +// of each call site is the same. +func callsites(sites []*CallSite, visited map[*FuncNode]bool) []*CallSite { + minCs := make(map[*FuncNode]*CallSite) + for _, cs := range sites { + if visited[cs.Parent] { + continue + } + if csLess(cs, minCs[cs.Parent]) { + minCs[cs.Parent] = cs + } + } + + var fs []*FuncNode + for _, cs := range minCs { + fs = append(fs, cs.Parent) + } + sort.SliceStable(fs, func(i, j int) bool { return funcLess(fs[i], fs[j]) }) + + var css []*CallSite + for _, f := range fs { + css = append(css, minCs[f]) + } + return css +} + +// callChain models a chain of function calls. +type callChain struct { + call *CallSite // nil for entry points + f *FuncNode + child *callChain +} + +// CallStack converts callChain to CallStack type. +func (c *callChain) CallStack() CallStack { + if c == nil { + return nil + } + return append(CallStack{StackEntry{Function: c.f, Call: c.call}}, c.child.CallStack()...) +} + +// weight computes an approximate measure of how easy is to understand the call +// stack when presented to the client as a witness. The smaller the value, the more +// understandable the stack is. Currently defined as the number of unresolved +// call sites in the stack. +func weight(stack CallStack) int { + w := 0 + for _, e := range stack { + if e.Call != nil && !e.Call.Resolved { + w += 1 + } + } + return w +} + +// csLess compares two call sites by their locations and, if needed, +// their string representation. +func csLess(cs1, cs2 *CallSite) bool { + if cs2 == nil { + return true + } + + // fast code path + if p1, p2 := cs1.Pos, cs2.Pos; p1 != nil && p2 != nil { + if posLess(*p1, *p2) { + return true + } + if posLess(*p2, *p1) { + return false + } + // for sanity, should not occur in practice + return fmt.Sprintf("%v.%v", cs1.RecvType, cs2.Name) < fmt.Sprintf("%v.%v", cs2.RecvType, cs2.Name) + } + + // code path rarely exercised + if cs2.Pos == nil { + return true + } + if cs1.Pos == nil { + return false + } + // should very rarely occur in practice + return fmt.Sprintf("%v.%v", cs1.RecvType, cs2.Name) < fmt.Sprintf("%v.%v", cs2.RecvType, cs2.Name) +} + +// posLess compares two positions by their line and column number, +// and filename if needed. +func posLess(p1, p2 token.Position) bool { + if p1.Line < p2.Line { + return true + } + if p2.Line < p1.Line { + return false + } + + if p1.Column < p2.Column { + return true + } + if p2.Column < p1.Column { + return false + } + + return strings.Compare(p1.Filename, p2.Filename) == -1 +} + +// funcLess compares two function nodes by locations of +// corresponding functions and, if needed, their string representation. +func funcLess(f1, f2 *FuncNode) bool { + if p1, p2 := f1.Pos, f2.Pos; p1 != nil && p2 != nil { + if posLess(*p1, *p2) { + return true + } + if posLess(*p2, *p1) { + return false + } + // for sanity, should not occur in practice + return f1.String() < f2.String() + } + + if f2.Pos == nil { + return true + } + if f1.Pos == nil { + return false + } + // should happen only for inits + return f1.String() < f2.String() +} + +// updateInitPositions populates non-existing positions of init functions +// and their respective calls in callStacks (see #51575). +func updateInitPositions(callStacks map[*Vuln]CallStack) { + for _, cs := range callStacks { + for i := range cs { + updateInitPosition(&cs[i]) + if i != len(cs)-1 { + updateInitCallPosition(&cs[i], cs[i+1]) + } + } + } +} + +// updateInitCallPosition updates the position of a call to init in a stack frame, if +// one already does not exist: +// +// P1.init -> P2.init: position of call to P2.init is the position of "import P2" +// statement in P1 +// +// P.init -> P.init#d: P.init is an implicit init. We say it calls the explicit +// P.init#d at the place of "package P" statement. +func updateInitCallPosition(curr *StackEntry, next StackEntry) { + call := curr.Call + if !isInit(next.Function) || (call.Pos != nil && call.Pos.IsValid()) { + // Skip non-init functions and inits whose call site position is available. + return + } + + var pos token.Position + if curr.Function.Name == "init" && curr.Function.Package == next.Function.Package { + // We have implicit P.init calling P.init#d. Set the call position to + // be at "package P" statement position. + pos = packageStatementPos(curr.Function.Package) + } else { + // Choose the beginning of the import statement as the position. + pos = importStatementPos(curr.Function.Package, next.Function.Package.PkgPath) + } + + call.Pos = &pos +} + +func importStatementPos(pkg *packages.Package, importPath string) token.Position { + var importSpec *ast.ImportSpec +spec: + for _, f := range pkg.Syntax { + for _, impSpec := range f.Imports { + // Import spec paths have quotation marks. + impSpecPath, err := strconv.Unquote(impSpec.Path.Value) + if err != nil { + panic(fmt.Sprintf("import specification: package path has no quotation marks: %v", err)) + } + if impSpecPath == importPath { + importSpec = impSpec + break spec + } + } + } + + if importSpec == nil { + // for sanity, in case of a wild call graph imprecision + return token.Position{} + } + + // Choose the beginning of the import statement as the position. + return pkg.Fset.Position(importSpec.Pos()) +} + +func packageStatementPos(pkg *packages.Package) token.Position { + if len(pkg.Syntax) == 0 { + return token.Position{} + } + // Choose beginning of the package statement as the position. Pick + // the first file since it is as good as any. + return pkg.Fset.Position(pkg.Syntax[0].Package) +} + +// updateInitPosition updates the position of P.init function in a stack frame if one +// is not available. The new position is the position of the "package P" statement. +func updateInitPosition(se *StackEntry) { + fun := se.Function + if !isInit(fun) || (fun.Pos != nil && fun.Pos.IsValid()) { + // Skip non-init functions and inits whose position is available. + return + } + + pos := packageStatementPos(fun.Package) + fun.Pos = &pos +} + +func isInit(f *FuncNode) bool { + // A source init function, or anonymous functions used in inits, will + // be named "init#x" by vulncheck (more precisely, ssa), where x is a + // positive integer. Implicit inits are named simply "init". + return f.Name == "init" || strings.HasPrefix(f.Name, "init#") +} + +// binaryCallstacks computes representative call stacks for binary results. +func binaryCallstacks(vr *Result) map[*Vuln]CallStack { + callstacks := map[*Vuln]CallStack{} + for _, vv := range uniqueVulns(vr.Vulns) { + f := &FuncNode{Package: vv.Package, Name: vv.Symbol} + parts := strings.Split(vv.Symbol, ".") + if len(parts) != 1 { + f.RecvType = parts[0] + f.Name = parts[1] + } + callstacks[vv] = CallStack{StackEntry{Function: f}} + } + return callstacks +} + +// uniqueVulns does for binary mode what sourceCallstacks does for source mode. +// It tries not to report redundant symbols. Since there are no call stacks in +// binary mode, the following approximate approach is used. Do not report unexported +// symbols for a triple if there are some exported symbols. +// Otherwise, report all unexported symbols to avoid not reporting anything. +func uniqueVulns(vulns []*Vuln) []*Vuln { + type key struct { + id string + pkg string + mod string + } + hasExported := make(map[key]bool) + for _, v := range vulns { + if isExported(v.Symbol) { + k := key{id: v.OSV.ID, pkg: v.Package.PkgPath, mod: v.Package.Module.Path} + hasExported[k] = true + } + } + + var uniques []*Vuln + for _, v := range vulns { + k := key{id: v.OSV.ID, pkg: v.Package.PkgPath, mod: v.Package.Module.Path} + if isExported(v.Symbol) || !hasExported[k] { + uniques = append(uniques, v) + } + } + return uniques +} + +// isExported checks if the symbol is exported. Assumes that the +// symbol is of the form "identifier" or "identifier1.identifier2". +func isExported(symbol string) bool { + parts := strings.Split(symbol, ".") + if len(parts) == 1 { + return unicode.IsUpper(rune(symbol[0])) + } + return unicode.IsUpper(rune(parts[1][0])) +} diff --git a/vendor/golang.org/x/vuln/internal/web/url.go b/vendor/golang.org/x/vuln/internal/web/url.go new file mode 100644 index 000000000..dadc6b4fe --- /dev/null +++ b/vendor/golang.org/x/vuln/internal/web/url.go @@ -0,0 +1,143 @@ +// Copyright 2022 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. + +// Code copied from +// https://github.com/golang/go/blob/2ebe77a2fda1ee9ff6fd9a3e08933ad1ebaea039/src/cmd/go/internal/web/url.go +// TODO(https://go.dev/issue/32456): if accepted, use the new API. + +package web + +import ( + "errors" + "net/url" + "path/filepath" + "runtime" + "strings" +) + +var errNotAbsolute = errors.New("path is not absolute") + +// URLToFilePath converts a file-scheme url to a file path. +func URLToFilePath(u *url.URL) (string, error) { + if u.Scheme != "file" { + return "", errors.New("non-file URL") + } + + checkAbs := func(path string) (string, error) { + if !filepath.IsAbs(path) { + return "", errNotAbsolute + } + return path, nil + } + + if u.Path == "" { + if u.Host != "" || u.Opaque == "" { + return "", errors.New("file URL missing path") + } + return checkAbs(filepath.FromSlash(u.Opaque)) + } + + path, err := convertFileURLPath(u.Host, u.Path) + if err != nil { + return path, err + } + return checkAbs(path) +} + +// URLFromFilePath converts the given absolute path to a URL. +func URLFromFilePath(path string) (*url.URL, error) { + if !filepath.IsAbs(path) { + return nil, errNotAbsolute + } + + // If path has a Windows volume name, convert the volume to a host and prefix + // per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/. + if vol := filepath.VolumeName(path); vol != "" { + if strings.HasPrefix(vol, `\\`) { + path = filepath.ToSlash(path[2:]) + i := strings.IndexByte(path, '/') + + if i < 0 { + // A degenerate case. + // \\host.example.com (without a share name) + // becomes + // file://host.example.com/ + return &url.URL{ + Scheme: "file", + Host: path, + Path: "/", + }, nil + } + + // \\host.example.com\Share\path\to\file + // becomes + // file://host.example.com/Share/path/to/file + return &url.URL{ + Scheme: "file", + Host: path[:i], + Path: filepath.ToSlash(path[i:]), + }, nil + } + + // C:\path\to\file + // becomes + // file:///C:/path/to/file + return &url.URL{ + Scheme: "file", + Path: "/" + filepath.ToSlash(path), + }, nil + } + + // /path/to/file + // becomes + // file:///path/to/file + return &url.URL{ + Scheme: "file", + Path: filepath.ToSlash(path), + }, nil +} + +func convertFileURLPath(host, path string) (string, error) { + if runtime.GOOS == "windows" { + return convertFileURLPathWindows(host, path) + } + switch host { + case "", "localhost": + default: + return "", errors.New("file URL specifies non-local host") + } + return filepath.FromSlash(path), nil +} + +func convertFileURLPathWindows(host, path string) (string, error) { + if len(path) == 0 || path[0] != '/' { + return "", errNotAbsolute + } + + path = filepath.FromSlash(path) + + // We interpret Windows file URLs per the description in + // https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/. + + // The host part of a file URL (if any) is the UNC volume name, + // but RFC 8089 reserves the authority "localhost" for the local machine. + if host != "" && host != "localhost" { + // A common "legacy" format omits the leading slash before a drive letter, + // encoding the drive letter as the host instead of part of the path. + // (See https://blogs.msdn.microsoft.com/freeassociations/2005/05/19/the-bizarre-and-unhappy-story-of-file-urls/.) + // We do not support that format, but we should at least emit a more + // helpful error message for it. + if filepath.VolumeName(host) != "" { + return "", errors.New("file URL encodes volume in host field: too few slashes?") + } + return `\\` + host + path, nil + } + + // If host is empty, path must contain an initial slash followed by a + // drive letter and path. Remove the slash and verify that the path is valid. + if vol := filepath.VolumeName(path[1:]); vol == "" || strings.HasPrefix(vol, `\\`) { + return "", errors.New("file URL missing drive letter") + } + return path[1:], nil +} diff --git a/vendor/golang.org/x/vuln/osv/json.go b/vendor/golang.org/x/vuln/osv/json.go deleted file mode 100644 index d3bc8659c..000000000 --- a/vendor/golang.org/x/vuln/osv/json.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2021 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 osv implements the OSV shared vulnerability -// format, as defined by https://ossf.github.io/osv-schema. -// -// As this package is intended for use with the Go vulnerability -// database, only the subset of features which are used by that -// database are implemented (for instance, only the SEMVER affected -// range type is implemented). -package osv - -import ( - "sort" - "time" - - "golang.org/x/mod/semver" - isem "golang.org/x/vuln/internal/semver" -) - -type AffectsRangeType string - -const ( - TypeUnspecified AffectsRangeType = "UNSPECIFIED" - TypeGit AffectsRangeType = "GIT" - TypeSemver AffectsRangeType = "SEMVER" -) - -type Ecosystem string - -const GoEcosystem Ecosystem = "Go" - -type Package struct { - Name string `json:"name"` - Ecosystem Ecosystem `json:"ecosystem"` -} - -type RangeEvent struct { - Introduced string `json:"introduced,omitempty"` - Fixed string `json:"fixed,omitempty"` -} - -type AffectsRange struct { - Type AffectsRangeType `json:"type"` - Events []RangeEvent `json:"events"` -} - -// containsSemver checks if semver version v is in the -// range encoded by ar. If ar is not a semver range, -// returns false. -// -// Assumes that -// - exactly one of Introduced or Fixed fields is set -// - ranges in ar are not overlapping -// - beginning of time is encoded with .Introduced="0" -// - no-fix is not an event, as opposed to being an -// event where Introduced="" and Fixed="" -func (ar AffectsRange) containsSemver(v string) bool { - if ar.Type != TypeSemver { - return false - } - if len(ar.Events) == 0 { - return true - } - - // Strip and then add the semver prefix so we can support bare versions, - // versions prefixed with 'v', and versions prefixed with 'go'. - v = isem.CanonicalizeSemverPrefix(v) - - // Sort events by semver versions. Event for beginning - // of time, if present, always comes first. - sort.SliceStable(ar.Events, func(i, j int) bool { - e1 := ar.Events[i] - v1 := e1.Introduced - if v1 == "0" { - // -inf case. - return true - } - if e1.Fixed != "" { - v1 = e1.Fixed - } - - e2 := ar.Events[j] - v2 := e2.Introduced - if v2 == "0" { - // -inf case. - return false - } - if e2.Fixed != "" { - v2 = e2.Fixed - } - - return semver.Compare(isem.CanonicalizeSemverPrefix(v1), isem.CanonicalizeSemverPrefix(v2)) < 0 - }) - - var affected bool - for _, e := range ar.Events { - if !affected && e.Introduced != "" { - affected = e.Introduced == "0" || semver.Compare(v, isem.CanonicalizeSemverPrefix(e.Introduced)) >= 0 - } else if affected && e.Fixed != "" { - affected = semver.Compare(v, isem.CanonicalizeSemverPrefix(e.Fixed)) < 0 - } - } - - return affected -} - -type Affects []AffectsRange - -func (a Affects) AffectsSemver(v string) bool { - if len(a) == 0 { - // No ranges implies all versions are affected - return true - } - var semverRangePresent bool - for _, r := range a { - if r.Type != TypeSemver { - continue - } - semverRangePresent = true - if r.containsSemver(v) { - return true - } - } - // If there were no semver ranges present we - // assume that all semvers are affected, similarly - // to how to we assume all semvers are affected - // if there are no ranges at all. - return !semverRangePresent -} - -type Reference struct { - Type string `json:"type"` - URL string `json:"url"` -} - -type Affected struct { - Package Package `json:"package"` - Ranges Affects `json:"ranges,omitempty"` - DatabaseSpecific DatabaseSpecific `json:"database_specific"` - EcosystemSpecific EcosystemSpecific `json:"ecosystem_specific"` -} - -type DatabaseSpecific struct { - URL string `json:"url"` -} - -// EcosytemSpecificImport contains additional information about an affected package. -type EcosystemSpecificImport struct { - // Path is the package import path. - Path string `json:"path,omitempty"` - - // GOOS is the execution operating system where the symbols appear, if - // known. - GOOS []string `json:"goos,omitempty"` - - // GOARCH specifies the execution architecture where the symbols appear, if - // known. - GOARCH []string `json:"goarch,omitempty"` - - // Symbols is the collection of functions and methods names affected by - // this vulnerability. Methods are listed as .. - // - // If included, only programs which use these symbols will be marked as - // vulnerable. If omitted, any program which imports this module will be - // marked vulnerable. - // - // These should be the symbols initially detected or identified in the CVE - // or other source. - Symbols []string `json:"symbols,omitempty"` -} - -// EcosystemSpecific contains additional information about the vulnerability -// for the Go ecosystem. -type EcosystemSpecific struct { - // Imports is the list of affected packages within the module. - Imports []EcosystemSpecificImport `json:"imports,omitempty"` -} - -// Entry represents a OSV style JSON vulnerability database -// entry -type Entry struct { - ID string `json:"id"` - Published time.Time `json:"published,omitempty"` - Modified time.Time `json:"modified,omitempty"` - Withdrawn *time.Time `json:"withdrawn,omitempty"` - Aliases []string `json:"aliases,omitempty"` - Details string `json:"details"` - Affected []Affected `json:"affected"` - References []Reference `json:"references,omitempty"` -} diff --git a/vendor/golang.org/x/vuln/scan/scan.go b/vendor/golang.org/x/vuln/scan/scan.go new file mode 100644 index 000000000..0aa9975e0 --- /dev/null +++ b/vendor/golang.org/x/vuln/scan/scan.go @@ -0,0 +1,106 @@ +// Copyright 2023 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 scan provides functionality for running govulncheck. + +See [cmd/govulncheck/main.go] as a usage example. + +[cmd/govulncheck/main.go]: https://go.googlesource.com/vuln/+/master/cmd/govulncheck/main.go +*/ +package scan + +import ( + "context" + "errors" + "io" + "os" + + "golang.org/x/vuln/internal/scan" +) + +// Cmd represents an external govulncheck command being prepared or run, +// similar to exec.Cmd. +type Cmd struct { + // Stdin specifies the standard input. If provided, it is expected to be + // the output of govulncheck -json. + Stdin io.Reader + + // Stdout specifies the standard output. If nil, Run connects os.Stdout. + Stdout io.Writer + + // Stderr specifies the standard error. If nil, Run connects os.Stderr. + Stderr io.Writer + + // Env is the environment to use. + // If Env is nil, the current environment is used. + // As in os/exec's Cmd, only the last value in the slice for + // each environment key is used. To specify the setting of only + // a few variables, append to the current environment, as in: + // + // opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386") + // + Env []string + + ctx context.Context + args []string + done chan struct{} + err error +} + +// Command returns the Cmd struct to execute govulncheck with the given +// arguments. +func Command(ctx context.Context, arg ...string) *Cmd { + return &Cmd{ + ctx: ctx, + args: arg, + } +} + +// Start starts the specified command but does not wait for it to complete. +// +// After a successful call to Start the Wait method must be called in order to +// release associated system resources. +func (c *Cmd) Start() error { + if c.done != nil { + return errors.New("vuln: already started") + } + if c.Stdin == nil { + c.Stdin = os.Stdin + } + if c.Stdout == nil { + c.Stdout = os.Stdout + } + if c.Stderr == nil { + c.Stderr = os.Stderr + } + if c.Env == nil { + c.Env = os.Environ() + } + c.done = make(chan struct{}) + go func() { + defer close(c.done) + c.err = c.scan() + }() + return nil +} + +// Wait waits for the command to exit. The command must have been started by +// Start. +// +// Wait releases any resources associated with the Cmd. +func (c *Cmd) Wait() error { + if c.done == nil { + return errors.New("vuln: start must be called before wait") + } + <-c.done + return c.err +} + +func (c *Cmd) scan() error { + if err := c.ctx.Err(); err != nil { + return err + } + return scan.RunGovulncheck(c.ctx, c.Env, c.Stdin, c.Stdout, c.Stderr, c.args) +} diff --git a/vendor/golang.org/x/vuln/vulncheck/binary.go b/vendor/golang.org/x/vuln/vulncheck/binary.go deleted file mode 100644 index c1fccd947..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/binary.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package vulncheck - -import ( - "context" - "fmt" - "io" - "runtime/debug" - "strings" - - "golang.org/x/tools/go/packages" - "golang.org/x/vuln/internal/derrors" - "golang.org/x/vuln/internal/semver" - "golang.org/x/vuln/vulncheck/internal/binscan" -) - -// Binary detects presence of vulnerable symbols in exe. -// The Calls, Imports, and Requires fields on Result will be empty. -func Binary(ctx context.Context, exe io.ReaderAt, cfg *Config) (_ *Result, err error) { - defer derrors.Wrap(&err, "vulncheck.Binary") - - mods, packageSymbols, bi, err := binscan.ExtractPackagesAndSymbols(exe) - if err != nil { - return nil, err - } - - cmods := convertModules(mods) - // set the stdlib version for detection of vulns in the standard library - // TODO(#53740): what if Go version is not in semver format? - stdlibModule.Version = semver.GoTagToSemver(bi.GoVersion) - // Add "stdlib" module. - cmods = append(cmods, stdlibModule) - - modVulns, err := fetchVulnerabilities(ctx, cfg.Client, cmods) - if err != nil { - return nil, err - } - - goos := findSetting("GOOS", bi) - goarch := findSetting("GOARCH", bi) - if goos == "" || goarch == "" { - fmt.Printf("warning: failed to extract build system specification GOOS: %s GOARCH: %s\n", goos, goarch) - } - - modVulns = modVulns.filter(goos, goarch) - result := &Result{} - for pkg, symbols := range packageSymbols { - mod := findPackageModule(pkg, cmods) - if cfg.ImportsOnly { - addImportsOnlyVulns(pkg, mod, symbols, result, modVulns) - } else { - addSymbolVulns(pkg, mod, symbols, result, modVulns) - } - } - setModules(result, cmods) - return result, nil -} - -// addImportsOnlyVulns adds Vuln entries to result in imports only mode, i.e., for each vulnerable symbol -// of pkg. -func addImportsOnlyVulns(pkg, mod string, symbols []string, result *Result, modVulns moduleVulnerabilities) { - for _, osv := range modVulns.vulnsForPackage(pkg) { - for _, affected := range osv.Affected { - for _, p := range affected.EcosystemSpecific.Imports { - if p.Path != pkg { - continue - } - syms := p.Symbols - if len(syms) == 0 { - // If every symbol of pkg is vulnerable, we would ideally - // compute every symbol mentioned in the pkg and then add - // Vuln entry for it, just as we do in Source. However, - // we don't have code of pkg here so we have to do best - // we can, which is the symbols of pkg actually appearing - // in the binary. - syms = symbols - } - - for _, symbol := range syms { - vuln := &Vuln{ - OSV: osv, - Symbol: symbol, - PkgPath: pkg, - ModPath: mod, - } - result.Vulns = append(result.Vulns, vuln) - } - } - } - } -} - -// addSymbolVulns adds Vuln entries to result for every symbol of pkg in the binary that is vulnerable. -func addSymbolVulns(pkg, mod string, symbols []string, result *Result, modVulns moduleVulnerabilities) { - for _, symbol := range symbols { - for _, osv := range modVulns.vulnsForSymbol(pkg, symbol) { - vuln := &Vuln{ - OSV: osv, - Symbol: symbol, - PkgPath: pkg, - ModPath: mod, - } - result.Vulns = append(result.Vulns, vuln) - } - } -} - -func convertModules(mods []*packages.Module) []*Module { - vmods := make([]*Module, len(mods)) - convertMod := newModuleConverter() - for i, mod := range mods { - vmods[i] = convertMod(mod) - } - return vmods -} - -// findPackageModule returns the path of a module that could contain the import -// path pkg. It uses paths only. It is possible but unlikely for a package path -// to match two or more different module paths. We just take the first one. -// If no module path matches, findPackageModule returns the empty string. -func findPackageModule(pkg string, mods []*Module) string { - if isStdPackage(pkg) { - return stdlibModule.Path - } - - for _, m := range mods { - if pkg == m.Path || strings.HasPrefix(pkg, m.Path+"/") { - return m.Path - } - } - return "" -} - -// findSetting returns value of setting from bi if present. -// Otherwise, returns "". -func findSetting(setting string, bi *debug.BuildInfo) string { - for _, s := range bi.Settings { - if s.Key == setting { - return s.Value - } - } - return "" -} diff --git a/vendor/golang.org/x/vuln/vulncheck/fetch.go b/vendor/golang.org/x/vuln/vulncheck/fetch.go deleted file mode 100644 index dc0e1c7d9..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/fetch.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2021 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 vulncheck - -import ( - "context" - "fmt" - - "golang.org/x/vuln/client" -) - -var stdlibModule = &Module{ - Path: "stdlib", - // Version is populated by Source and Binary based on user input -} - -// modKey creates a unique string identifier for mod. -func modKey(mod *Module) string { - if mod == nil { - return "" - } - return fmt.Sprintf("%s@%s", mod.Path, mod.Version) -} - -// extractModules collects modules in `pkgs` up to uniqueness of -// module path and version. -func extractModules(pkgs []*Package) []*Module { - modMap := map[string]*Module{} - - // Add "stdlib" module. Even if stdlib is not used, which - // is unlikely, it won't appear in vulncheck.Modules nor - // other results. - modMap[stdlibModule.Path] = stdlibModule - - seen := map[*Package]bool{} - var extract func(*Package, map[string]*Module) - extract = func(pkg *Package, modMap map[string]*Module) { - if pkg == nil || seen[pkg] { - return - } - if pkg.Module != nil { - if pkg.Module.Replace != nil { - modMap[modKey(pkg.Module.Replace)] = pkg.Module - } else { - modMap[modKey(pkg.Module)] = pkg.Module - } - } - seen[pkg] = true - for _, imp := range pkg.Imports { - extract(imp, modMap) - } - } - for _, pkg := range pkgs { - extract(pkg, modMap) - } - - modules := []*Module{} - for _, mod := range modMap { - modules = append(modules, mod) - } - return modules -} - -// fetchVulnerabilities fetches vulnerabilities that affect the supplied modules. -func fetchVulnerabilities(ctx context.Context, client client.Client, modules []*Module) (moduleVulnerabilities, error) { - mv := moduleVulnerabilities{} - for _, mod := range modules { - modPath := mod.Path - if mod.Replace != nil { - modPath = mod.Replace.Path - } - - vulns, err := client.GetByModule(ctx, modPath) - if err != nil { - return nil, err - } - if len(vulns) == 0 { - continue - } - mv = append(mv, modVulns{ - mod: mod, - vulns: vulns, - }) - } - return mv, nil -} diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/binscan/exe.go b/vendor/golang.org/x/vuln/vulncheck/internal/binscan/exe.go deleted file mode 100644 index 4d09f9fb5..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/internal/binscan/exe.go +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package binscan - -// This file is a somewhat modified version of cmd/go/internal/version/exe.go -// that adds functionality for extracting the PCLN table. - -import ( - "bytes" - "debug/elf" - "debug/macho" - "debug/pe" - "encoding/binary" - "fmt" - - // "internal/xcoff" - "io" -) - -// An exe is a generic interface to an OS executable (ELF, Mach-O, PE, XCOFF). -type exe interface { - // ReadData reads and returns up to size byte starting at virtual address addr. - ReadData(addr, size uint64) ([]byte, error) - - // DataStart returns the writable data segment start address. - DataStart() uint64 - - PCLNTab() ([]byte, uint64) - - SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) -} - -// openExe returns reader r as an exe. -func openExe(r io.ReaderAt) (exe, error) { - data := make([]byte, 16) - if _, err := r.ReadAt(data, 0); err != nil { - return nil, err - } - if bytes.HasPrefix(data, []byte("\x7FELF")) { - e, err := elf.NewFile(r) - if err != nil { - return nil, err - } - return &elfExe{e}, nil - } - if bytes.HasPrefix(data, []byte("MZ")) { - e, err := pe.NewFile(r) - if err != nil { - return nil, err - } - return &peExe{r, e}, nil - } - if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) { - e, err := macho.NewFile(r) - if err != nil { - return nil, err - } - return &machoExe{e}, nil - } - // TODO(rolandshoemaker): we cannot support XCOFF files due to the usage of internal/xcoff. - // Once this code is moved into the stdlib, this support can be re-enabled. - // if bytes.HasPrefix(data, []byte{0x01, 0xDF}) || bytes.HasPrefix(data, []byte{0x01, 0xF7}) { - // e, err := xcoff.NewFile(r) - // if err != nil { - // return nil, err - // } - // return &xcoffExe{e}, nil - - // } - return nil, fmt.Errorf("unrecognized executable format") -} - -// elfExe is the ELF implementation of the exe interface. -type elfExe struct { - f *elf.File -} - -func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) { - for _, prog := range x.f.Progs { - if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 { - n := prog.Vaddr + prog.Filesz - addr - if n > size { - n = size - } - data := make([]byte, n) - _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)) - if err != nil { - return nil, err - } - return data, nil - } - } - return nil, fmt.Errorf("address not mapped") -} - -func (x *elfExe) DataStart() uint64 { - for _, s := range x.f.Sections { - if s.Name == ".go.buildinfo" { - return s.Addr - } - } - for _, p := range x.f.Progs { - if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W { - return p.Vaddr - } - } - return 0 -} - -func (x *elfExe) SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) { - sym := x.lookupSymbol(name) - if sym == nil { - return 0, 0, nil, fmt.Errorf("no symbol %q", name) - } - prog := x.progContaining(sym.Value) - if prog == nil { - return 0, 0, nil, fmt.Errorf("no Prog containing value %d for %q", sym.Value, name) - } - return sym.Value, prog.Vaddr, prog.ReaderAt, nil -} - -func (x *elfExe) lookupSymbol(name string) *elf.Symbol { - syms, err := x.f.Symbols() - if err != nil { - return nil - } - for _, s := range syms { - if s.Name == name { - return &s - } - } - return nil -} - -func (x *elfExe) progContaining(addr uint64) *elf.Prog { - for _, p := range x.f.Progs { - if addr >= p.Vaddr && addr < p.Vaddr+p.Filesz { - return p - } - } - return nil -} - -const go12magic = 0xfffffffb -const go116magic = 0xfffffffa - -func (x *elfExe) PCLNTab() ([]byte, uint64) { - var offset uint64 - text := x.f.Section(".text") - if text != nil { - offset = text.Offset - } - pclntab := x.f.Section(".gopclntab") - if pclntab == nil { - pclntab = x.f.Section(".data.rel.ro.gopclntab") - if pclntab == nil { - pclntab = x.f.Section(".data.rel.ro") - if pclntab == nil { - return nil, 0 - } - // Possibly the PCLN table has been stuck in the .data.rel.ro section, but without - // its own section header. We can search for for the start by looking for the four - // byte magic and the go magic. - b, err := pclntab.Data() - if err != nil { - return nil, 0 - } - // TODO(rolandshoemaker): I'm not sure if the 16 byte increment during the search is - // actually correct. During testing it worked, but that may be because I got lucky - // with the binary I was using, and we need to do four byte jumps to exhaustively - // search the section? - for i := 0; i < len(b); i += 16 { - if len(b)-i > 16 && b[i+4] == 0 && b[i+5] == 0 && - (b[i+6] == 1 || b[i+6] == 2 || b[i+6] == 4) && - (b[i+7] == 4 || b[i+7] == 8) { - // Also check for the go magic - leMagic := binary.LittleEndian.Uint32(b[i:]) - beMagic := binary.BigEndian.Uint32(b[i:]) - switch { - case leMagic == go12magic: - fallthrough - case beMagic == go12magic: - fallthrough - case leMagic == go116magic: - fallthrough - case beMagic == go116magic: - return b[i:], offset - } - } - } - } - } - b, err := pclntab.Data() - if err != nil { - return nil, 0 - } - return b, offset -} - -// peExe is the PE (Windows Portable Executable) implementation of the exe interface. -type peExe struct { - r io.ReaderAt - f *pe.File -} - -func (x *peExe) imageBase() uint64 { - switch oh := x.f.OptionalHeader.(type) { - case *pe.OptionalHeader32: - return uint64(oh.ImageBase) - case *pe.OptionalHeader64: - return oh.ImageBase - } - return 0 -} - -func (x *peExe) ReadData(addr, size uint64) ([]byte, error) { - addr -= x.imageBase() - for _, sect := range x.f.Sections { - if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) { - n := uint64(sect.VirtualAddress+sect.Size) - addr - if n > size { - n = size - } - data := make([]byte, n) - _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress))) - if err != nil { - return nil, err - } - return data, nil - } - } - return nil, fmt.Errorf("address not mapped") -} - -func (x *peExe) DataStart() uint64 { - // Assume data is first writable section. - const ( - IMAGE_SCN_CNT_CODE = 0x00000020 - IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 - IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 - IMAGE_SCN_MEM_EXECUTE = 0x20000000 - IMAGE_SCN_MEM_READ = 0x40000000 - IMAGE_SCN_MEM_WRITE = 0x80000000 - IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 - IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 - IMAGE_SCN_ALIGN_32BYTES = 0x600000 - ) - for _, sect := range x.f.Sections { - if sect.VirtualAddress != 0 && sect.Size != 0 && - sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE { - return uint64(sect.VirtualAddress) + x.imageBase() - } - } - return 0 -} - -func (x *peExe) SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) { - sym := x.lookupSymbol(name) - if sym == nil { - return 0, 0, nil, fmt.Errorf("no symbol %q", name) - } - sect := x.f.Sections[sym.SectionNumber-1] - // In PE, the symbol's value is the offset from the section start. - return uint64(sym.Value), 0, sect.ReaderAt, nil -} - -func (x *peExe) lookupSymbol(name string) *pe.Symbol { - for _, s := range x.f.Symbols { - if s.Name == name { - return s - } - } - return nil -} - -func (x *peExe) PCLNTab() ([]byte, uint64) { - var textOffset uint64 - for _, section := range x.f.Sections { - if section.Name == ".text" { - textOffset = uint64(section.Offset) - break - } - } - var start, end int64 - var section int - for _, symbol := range x.f.Symbols { - if symbol.Name == "runtime.pclntab" { - start = int64(symbol.Value) - section = int(symbol.SectionNumber - 1) - } else if symbol.Name == "runtime.epclntab" { - end = int64(symbol.Value) - break - } - } - if start == 0 || end == 0 { - return nil, 0 - } - offset := int64(x.f.Sections[section].Offset) + start - size := end - start - - pclntab := make([]byte, size) - if _, err := x.r.ReadAt(pclntab, offset); err != nil { - return nil, 0 - } - return pclntab, textOffset -} - -// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface. -type machoExe struct { - f *macho.File -} - -func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) { - for _, load := range x.f.Loads { - seg, ok := load.(*macho.Segment) - if !ok { - continue - } - if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 { - if seg.Name == "__PAGEZERO" { - continue - } - n := seg.Addr + seg.Filesz - addr - if n > size { - n = size - } - data := make([]byte, n) - _, err := seg.ReadAt(data, int64(addr-seg.Addr)) - if err != nil { - return nil, err - } - return data, nil - } - } - return nil, fmt.Errorf("address not mapped") -} - -func (x *machoExe) DataStart() uint64 { - // Look for section named "__go_buildinfo". - for _, sec := range x.f.Sections { - if sec.Name == "__go_buildinfo" { - return sec.Addr - } - } - // Try the first non-empty writable segment. - const RW = 3 - for _, load := range x.f.Loads { - seg, ok := load.(*macho.Segment) - if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW { - return seg.Addr - } - } - return 0 -} - -func (x *machoExe) SymbolInfo(name string) (uint64, uint64, io.ReaderAt, error) { - sym := x.lookupSymbol(name) - if sym == nil { - return 0, 0, nil, fmt.Errorf("no symbol %q", name) - } - seg := x.segmentContaining(sym.Value) - if seg == nil { - return 0, 0, nil, fmt.Errorf("no Segment containing value %d for %q", sym.Value, name) - } - return sym.Value, seg.Addr, seg.ReaderAt, nil -} - -func (x *machoExe) lookupSymbol(name string) *macho.Symbol { - for _, s := range x.f.Symtab.Syms { - if s.Name == name { - return &s - } - } - return nil -} - -func (x *machoExe) segmentContaining(addr uint64) *macho.Segment { - for _, load := range x.f.Loads { - seg, ok := load.(*macho.Segment) - if ok && seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 && seg.Name != "__PAGEZERO" { - return seg - } - } - return nil -} - -func (x *machoExe) PCLNTab() ([]byte, uint64) { - var textOffset uint64 - text := x.f.Section("__text") - if text != nil { - textOffset = uint64(text.Offset) - } - pclntab := x.f.Section("__gopclntab") - if pclntab == nil { - return nil, 0 - } - b, err := pclntab.Data() - if err != nil { - return nil, 0 - } - return b, textOffset -} - -// TODO(rolandshoemaker): we cannot support XCOFF files due to the usage of internal/xcoff. -// Once this code is moved into the stdlib, this support can be re-enabled. - -// // xcoffExe is the XCOFF (AIX eXtended COFF) implementation of the exe interface. -// type xcoffExe struct { -// f *xcoff.File -// } -// -// func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) { -// for _, sect := range x.f.Sections { -// if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) { -// n := uint64(sect.VirtualAddress+sect.Size) - addr -// if n > size { -// n = size -// } -// data := make([]byte, n) -// _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress))) -// if err != nil { -// return nil, err -// } -// return data, nil -// } -// } -// return nil, fmt.Errorf("address not mapped") -// } -// -// func (x *xcoffExe) DataStart() uint64 { -// return x.f.SectionByType(xcoff.STYP_DATA).VirtualAddress -// } diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/README.md b/vendor/golang.org/x/vuln/vulncheck/internal/gosym/README.md deleted file mode 100644 index efc543149..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/README.md +++ /dev/null @@ -1,4 +0,0 @@ -This code was copied from src/debug/gosym in the go repo at commit 29604312784cfbf530fcf54837b7cf42c0500d0b. - -It was modified to remove dependencies on internal packages in the go repo, -and to compile under go 1.17. diff --git a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/sym.go b/vendor/golang.org/x/vuln/vulncheck/internal/gosym/sym.go deleted file mode 100644 index 7d5eb2067..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/internal/gosym/sym.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 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 gosym - -import ( - "strings" - - sv "golang.org/x/mod/semver" - "golang.org/x/vuln/internal/semver" -) - -const ( - funcSymNameGo119Lower string = "go.func.*" - funcSymNameGo120 string = "go:func.*" -) - -// FuncSymName returns symbol name for Go functions -// used in binaries based on Go version. Supported -// Go versions are 1.18, 1.19, and 1.20. Otherwise, -// returns an empty string. -func FuncSymName(goVersion string) string { - // Support devel goX.Y... - v := strings.TrimPrefix(goVersion, "devel ") - v = semver.GoTagToSemver(v) - mm := sv.MajorMinor(v) - if mm == "v1.18" || mm == "v1.19" { - return funcSymNameGo119Lower - } else if mm == "v1.20" { - return funcSymNameGo120 - } else if v == "" && strings.HasPrefix(goVersion, "devel") { - // We currently don't have a direct way of mapping - // Go versions of the form devel to semver, - // so we map it to the most recent supported major - // Go version, which is currently go1.20. - return funcSymNameGo120 - } - return "" -} diff --git a/vendor/golang.org/x/vuln/vulncheck/lib.sh b/vendor/golang.org/x/vuln/vulncheck/lib.sh deleted file mode 100644 index 1304d3a67..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/lib.sh +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2021 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. - -# Library of useful bash functions and variables. - -RED=; GREEN=; YELLOW=; NORMAL=; -MAXWIDTH=0 - -if tput setaf 1 >& /dev/null; then - RED=`tput setaf 1` - GREEN=`tput setaf 2` - YELLOW=`tput setaf 3` - NORMAL=`tput sgr0` - MAXWIDTH=$(( $(tput cols) - 2 )) -fi - -EXIT_CODE=0 - -info() { echo -e "${GREEN}$@${NORMAL}" 1>&2; } -warn() { echo -e "${YELLOW}$@${NORMAL}" 1>&2; } -err() { echo -e "${RED}$@${NORMAL}" 1>&2; EXIT_CODE=1; } - -die() { - err $@ - exit 1 -} - -dryrun=false - -# runcmd prints an info log describing the command that is about to be run, and -# then runs it. It sets EXIT_CODE to non-zero if the command fails, but does not exit -# the script. -runcmd() { - msg="$@" - if $dryrun; then - echo -e "${YELLOW}dryrun${GREEN}\$ $msg${NORMAL}" - return 0 - fi - # Truncate command logging for narrow terminals. - # Account for the 2 characters of '$ '. - if [[ $MAXWIDTH -gt 0 && ${#msg} -gt $MAXWIDTH ]]; then - msg="${msg::$(( MAXWIDTH - 3 ))}..." - fi - - echo -e "$@\n" 1>&2; - $@ || err "command failed" -} - -# tfvar NAME returns the value of NAME in the terraform.tfvars file. -tfvar() { - local name=$1 - awk '$1 == "'$name'" { print substr($3, 2, length($3)-2) }' terraform/terraform.tfvars -} diff --git a/vendor/golang.org/x/vuln/vulncheck/slicing.go b/vendor/golang.org/x/vuln/vulncheck/slicing.go deleted file mode 100644 index 7f7678746..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/slicing.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2021 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 vulncheck - -import ( - "golang.org/x/tools/go/callgraph" - "golang.org/x/tools/go/ssa" -) - -// forwardReachableFrom computes the set of functions forward reachable from `sources`. -// A function f is reachable from a function g if f is an anonymous function defined -// in g or a function called in g as given by the callgraph `cg`. -func forwardReachableFrom(sources map[*ssa.Function]bool, cg *callgraph.Graph) map[*ssa.Function]bool { - m := make(map[*ssa.Function]bool) - for s := range sources { - forward(s, cg, m) - } - return m -} - -func forward(f *ssa.Function, cg *callgraph.Graph, seen map[*ssa.Function]bool) { - if seen[f] { - return - } - seen[f] = true - var buf [10]*ssa.Value // avoid alloc in common case - for _, b := range f.Blocks { - for _, instr := range b.Instrs { - switch i := instr.(type) { - case ssa.CallInstruction: - for _, c := range siteCallees(i, cg) { - forward(c, cg, seen) - } - default: - for _, op := range i.Operands(buf[:0]) { - if fn, ok := (*op).(*ssa.Function); ok { - forward(fn, cg, seen) - } - } - } - } - } -} - -// pruneSet removes functions in `set` that are in `toPrune`. -func pruneSet(set, toPrune map[*ssa.Function]bool) { - for f := range set { - if !toPrune[f] { - delete(set, f) - } - } -} diff --git a/vendor/golang.org/x/vuln/vulncheck/source.go b/vendor/golang.org/x/vuln/vulncheck/source.go deleted file mode 100644 index 533c6f270..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/source.go +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright 2021 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 vulncheck - -import ( - "context" - "fmt" - "go/token" - "runtime" - "sort" - - "golang.org/x/tools/go/callgraph" - "golang.org/x/tools/go/ssa" - "golang.org/x/vuln/internal/derrors" - "golang.org/x/vuln/internal/semver" - "golang.org/x/vuln/osv" -) - -// Source detects vulnerabilities in packages. The result will contain: -// -// 1) An ImportGraph related to an import of a package with some known -// vulnerabilities. -// -// 2) A RequireGraph related to a require of a module with a package that has -// some known vulnerabilities. -// -// 3) A CallGraph leading to the use of a known vulnerable function or method. -func Source(ctx context.Context, pkgs []*Package, cfg *Config) (_ *Result, err error) { - defer derrors.Wrap(&err, "vulncheck.Source") - - // buildSSA builds a whole program that assumes all packages use the same FileSet. - // Check all packages in pkgs are using the same FileSet. - // TODO(hyangah): Alternative is to take FileSet out of Package and - // let Source take a single FileSet. That will make the enforcement - // clearer from the API level. - var fset *token.FileSet - for _, p := range pkgs { - if fset == nil { - fset = p.Fset - } else { - if fset != p.Fset { - return nil, fmt.Errorf("[]*Package must have created with the same FileSet") - } - } - } - - // set the stdlib version for detection of vulns in the standard library - // TODO(#53740): what if Go version is not in semver format? - if cfg.SourceGoVersion != "" { - stdlibModule.Version = semver.GoTagToSemver(cfg.SourceGoVersion) - } else { - stdlibModule.Version = semver.GoTagToSemver(runtime.Version()) - } - - mods := extractModules(pkgs) - modVulns, err := fetchVulnerabilities(ctx, cfg.Client, mods) - if err != nil { - return nil, err - } - modVulns = modVulns.filter(cfg.GOOS, cfg.GOARCH) - result := &Result{ - Imports: &ImportGraph{Packages: make(map[int]*PkgNode)}, - Requires: &RequireGraph{Modules: make(map[int]*ModNode)}, - Calls: &CallGraph{Functions: make(map[int]*FuncNode)}, - } - - vulnPkgModSlice(pkgs, modVulns, result) - setModules(result, mods) - // Return result immediately if in ImportsOnly mode or - // if there are no vulnerable packages, as there is no - // need to build the call graph. - if cfg.ImportsOnly || len(result.Imports.Packages) == 0 { - return result, nil - } - - prog, ssaPkgs := buildSSA(pkgs, fset) - entries := entryPoints(ssaPkgs) - cg := callGraph(prog, entries) - vulnCallGraphSlice(entries, modVulns, cg, result) - return result, nil -} - -// Set r.Modules to an adjusted list of modules. -func setModules(r *Result, mods []*Module) { - // Remove Dirs from modules; they aren't needed and complicate testing. - for _, m := range mods { - m.Dir = "" - if m.Replace != nil { - m.Replace.Dir = "" - } - } - // Sort for determinism. - sort.Slice(mods, func(i, j int) bool { return mods[i].Path < mods[j].Path }) - r.Modules = append(r.Modules, mods...) -} - -// pkgID is an id counter for nodes of Imports graph. -var pkgID int = 0 - -func nextPkgID() int { - pkgID++ - return pkgID -} - -// vulnPkgModSlice computes the slice of pkgs imports and requires graph -// leading to imports/requires of vulnerable packages/modules in modVulns -// and stores the computed slices to result. -func vulnPkgModSlice(pkgs []*Package, modVulns moduleVulnerabilities, result *Result) { - // analyzedPkgs contains information on packages analyzed thus far. - // If a package is mapped to nil, this means it has been visited - // but it does not lead to a vulnerable imports. Otherwise, a - // visited package is mapped to Imports package node. - analyzedPkgs := make(map[*Package]*PkgNode) - for _, pkg := range pkgs { - // Top level packages that lead to vulnerable imports are - // stored as result.Imports graph entry points. - if e := vulnImportSlice(pkg, modVulns, result, analyzedPkgs); e != nil { - result.Imports.Entries = append(result.Imports.Entries, e.ID) - } - } - - // Populate module requires slice as an overlay - // of package imports slice. - vulnModuleSlice(result) -} - -// vulnImportSlice checks if pkg has some vulnerabilities or transitively imports -// a package with known vulnerabilities. If that is the case, populates result.Imports -// graph with this reachability information and returns the result.Imports package -// node for pkg. Otherwise, returns nil. -func vulnImportSlice(pkg *Package, modVulns moduleVulnerabilities, result *Result, analyzed map[*Package]*PkgNode) *PkgNode { - if pn, ok := analyzed[pkg]; ok { - return pn - } - analyzed[pkg] = nil - // Recursively compute which direct dependencies lead to an import of - // a vulnerable package and remember the nodes of such dependencies. - var onSlice []*PkgNode - for _, imp := range pkg.Imports { - if impNode := vulnImportSlice(imp, modVulns, result, analyzed); impNode != nil { - onSlice = append(onSlice, impNode) - } - } - - // Check if pkg has known vulnerabilities. - vulns := modVulns.vulnsForPackage(pkg.PkgPath) - - // If pkg is not vulnerable nor it transitively leads - // to vulnerabilities, jump out. - if len(onSlice) == 0 && len(vulns) == 0 { - return nil - } - - // Module id gets populated later. - id := nextPkgID() - pkgNode := &PkgNode{ - ID: id, - Name: pkg.Name, - Path: pkg.PkgPath, - pkg: pkg, - } - analyzed[pkg] = pkgNode - - result.Imports.Packages[id] = pkgNode - - // Save node predecessor information. - for _, impSliceNode := range onSlice { - impSliceNode.ImportedBy = append(impSliceNode.ImportedBy, id) - } - - // Create Vuln entry for each symbol of known OSV entries for pkg. - for _, osv := range vulns { - for _, affected := range osv.Affected { - for _, p := range affected.EcosystemSpecific.Imports { - if p.Path != pkgNode.Path { - continue - } - - symbols := p.Symbols - if len(symbols) == 0 { - symbols = allSymbols(pkg.Pkg) - } - - for _, symbol := range symbols { - vuln := &Vuln{ - OSV: osv, - Symbol: symbol, - PkgPath: pkgNode.Path, - ImportSink: id, - } - result.Vulns = append(result.Vulns, vuln) - } - } - } - } - return pkgNode -} - -// vulnModuleSlice populates result.Requires as an overlay -// of result.Imports. -func vulnModuleSlice(result *Result) { - // Map from module nodes, identified with their - // path and version, to their unique ids. - modNodeIDs := make(map[string]int) - // We first collect inverse requires by (predecessor) - // relation on module node ids. - modPredRelation := make(map[int]map[int]bool) - // Sort keys so modules are assigned IDs deterministically, for tests. - var pkgIDs []int - for id := range result.Imports.Packages { - pkgIDs = append(pkgIDs, id) - } - sort.Ints(pkgIDs) - for _, id := range pkgIDs { - pkgNode := result.Imports.Packages[id] - // Create or get module node for pkgNode. - modID := moduleNodeID(pkgNode, result, modNodeIDs) - pkgNode.Module = modID - - // Update the set of predecessors. - if _, ok := modPredRelation[modID]; !ok { - modPredRelation[modID] = make(map[int]bool) - } - predSet := modPredRelation[modID] - - for _, predPkgID := range pkgNode.ImportedBy { - predModID := moduleNodeID(result.Imports.Packages[predPkgID], result, modNodeIDs) - // We don't add module edges for imports - // of packages in the same module as that - // will create self-loops in Requires graphs. - if predModID == modID { - continue - } - predSet[predModID] = true - } - } - - // Add entry module IDs. - seenEntries := make(map[int]bool) - for _, epID := range result.Imports.Entries { - entryModID := moduleNodeID(result.Imports.Packages[epID], result, modNodeIDs) - if seenEntries[entryModID] { - continue - } - seenEntries[entryModID] = true - result.Requires.Entries = append(result.Requires.Entries, entryModID) - } - - // Store the predecessor requires relation to result. - for modID := range modPredRelation { - if modID == 0 { - continue - } - - var predIDs []int - for predID := range modPredRelation[modID] { - predIDs = append(predIDs, predID) - } - modNode := result.Requires.Modules[modID] - modNode.RequiredBy = predIDs - } - - // And finally update Vulns with module information. - for _, vuln := range result.Vulns { - pkgNode := result.Imports.Packages[vuln.ImportSink] - modNode := result.Requires.Modules[pkgNode.Module] - - vuln.RequireSink = pkgNode.Module - vuln.ModPath = modNode.Path - } -} - -// modID is an id counter for nodes of Requires graph. -var modID int = 0 - -func nextModID() int { - modID++ - return modID -} - -// moduleNode creates a module node associated with pkgNode, if one does -// not exist already, and returns id of the module node. The actual module -// node is stored to result. -func moduleNodeID(pkgNode *PkgNode, result *Result, modNodeIDs map[string]int) int { - mod := pkgNode.pkg.Module - if isStdPackage(pkgNode.Path) { - // standard library packages don't have a module. - mod = stdlibModule - } - if mod == nil { - return 0 - } - - mk := modKey(mod) - if id, ok := modNodeIDs[mk]; ok { - return id - } - - id := nextModID() - n := &ModNode{ - ID: id, - Path: mod.Path, - Version: mod.Version, - } - result.Requires.Modules[id] = n - modNodeIDs[mk] = id - - // Create a replace module too when applicable. - if mod.Replace != nil { - rmk := modKey(mod.Replace) - if rid, ok := modNodeIDs[rmk]; ok { - n.Replace = rid - } else { - rid := nextModID() - rn := &ModNode{ - Path: mod.Replace.Path, - Version: mod.Replace.Version, - } - result.Requires.Modules[rid] = rn - modNodeIDs[rmk] = rid - n.Replace = rid - } - } - return id -} - -// vulnCallGraphSlice checks if known vulnerabilities are transitively reachable from sources -// via call graph cg. If so, populates result.Calls graph with this reachability information. -func vulnCallGraphSlice(sources []*ssa.Function, modVulns moduleVulnerabilities, cg *callgraph.Graph, result *Result) { - sinksWithVulns := vulnFuncs(cg, modVulns) - - // Compute call graph backwards reachable - // from vulnerable functions and methods. - var sinks []*callgraph.Node - for n := range sinksWithVulns { - sinks = append(sinks, n) - } - bcg := callGraphSlice(sinks, false) - - // Interesect backwards call graph with forward - // reachable graph to remove redundant edges. - var filteredSources []*callgraph.Node - for _, e := range sources { - if n, ok := bcg.Nodes[e]; ok { - filteredSources = append(filteredSources, n) - } - } - fcg := callGraphSlice(filteredSources, true) - - // Get the sinks that are in fact reachable from entry points. - filteredSinks := make(map[*callgraph.Node][]*osv.Entry) - for n, vs := range sinksWithVulns { - if fn, ok := fcg.Nodes[n.Func]; ok { - filteredSinks[fn] = vs - } - } - - // Transform the resulting call graph slice into - // vulncheck representation and store it to result. - vulnCallGraph(filteredSources, filteredSinks, result) -} - -// callGraphSlice computes a slice of callgraph beginning at starts -// in the direction (forward/backward) controlled by forward flag. -func callGraphSlice(starts []*callgraph.Node, forward bool) *callgraph.Graph { - g := &callgraph.Graph{Nodes: make(map[*ssa.Function]*callgraph.Node)} - - visited := make(map[*callgraph.Node]bool) - var visit func(*callgraph.Node) - visit = func(n *callgraph.Node) { - if visited[n] { - return - } - visited[n] = true - - var edges []*callgraph.Edge - if forward { - edges = n.Out - } else { - edges = n.In - } - - for _, edge := range edges { - nCallee := g.CreateNode(edge.Callee.Func) - nCaller := g.CreateNode(edge.Caller.Func) - callgraph.AddEdge(nCaller, edge.Site, nCallee) - - if forward { - visit(edge.Callee) - } else { - visit(edge.Caller) - } - } - } - - for _, s := range starts { - visit(s) - } - return g -} - -// funID is an id counter for nodes of Calls graph. -var funID int = 0 - -func nextFunID() int { - funID++ - return funID -} - -// vulnCallGraph creates vulnerability call graph from sources -> sinks reachability info. -func vulnCallGraph(sources []*callgraph.Node, sinks map[*callgraph.Node][]*osv.Entry, result *Result) { - nodes := make(map[*ssa.Function]*FuncNode) - createNode := func(f *ssa.Function) *FuncNode { - if fn, ok := nodes[f]; ok { - return fn - } - fn := funcNode(f) - nodes[f] = fn - result.Calls.Functions[fn.ID] = fn - return fn - } - - // First create entries and sinks and store relevant information. - for _, s := range sources { - fn := createNode(s.Func) - result.Calls.Entries = append(result.Calls.Entries, fn.ID) - } - - for s, vulns := range sinks { - f := s.Func - funNode := createNode(s.Func) - - // Populate CallSink field for each detected vuln symbol. - for _, osv := range vulns { - if vulnMatchesPackage(osv, funNode.PkgPath) { - addCallSinkForVuln(funNode.ID, osv, dbFuncName(f), funNode.PkgPath, result) - } - } - } - - visited := make(map[*callgraph.Node]bool) - var visit func(*callgraph.Node) - visit = func(n *callgraph.Node) { - if visited[n] { - return - } - visited[n] = true - - for _, edge := range n.In { - nCallee := createNode(edge.Callee.Func) - nCaller := createNode(edge.Caller.Func) - - call := edge.Site - cs := &CallSite{ - Parent: nCaller.ID, - Name: call.Common().Value.Name(), - RecvType: callRecvType(call), - Resolved: resolved(call), - Pos: instrPosition(call), - } - nCallee.CallSites = append(nCallee.CallSites, cs) - - visit(edge.Caller) - } - } - - for s := range sinks { - visit(s) - } -} - -// vulnFuncs returns vulnerability information for vulnerable functions in cg. -func vulnFuncs(cg *callgraph.Graph, modVulns moduleVulnerabilities) map[*callgraph.Node][]*osv.Entry { - m := make(map[*callgraph.Node][]*osv.Entry) - for f, n := range cg.Nodes { - vulns := modVulns.vulnsForSymbol(pkgPath(f), dbFuncName(f)) - if len(vulns) > 0 { - m[n] = vulns - } - } - return m -} - -// pkgPath returns the path of the f's enclosing package, if any. -// Otherwise, returns "". -func pkgPath(f *ssa.Function) string { - if f.Package() != nil && f.Package().Pkg != nil { - return f.Package().Pkg.Path() - } - return "" -} - -func funcNode(f *ssa.Function) *FuncNode { - id := nextFunID() - return &FuncNode{ - ID: id, - Name: f.Name(), - PkgPath: pkgPath(f), - RecvType: funcRecvType(f), - Pos: funcPosition(f), - } -} - -// addCallSinkForVuln adds callID as call sink to vuln of result.Vulns -// identified with . -func addCallSinkForVuln(callID int, osv *osv.Entry, symbol, pkg string, result *Result) { - for _, vuln := range result.Vulns { - if vuln.OSV == osv && vuln.Symbol == symbol && vuln.PkgPath == pkg { - vuln.CallSink = callID - return - } - } -} diff --git a/vendor/golang.org/x/vuln/vulncheck/vulncheck.go b/vendor/golang.org/x/vuln/vulncheck/vulncheck.go deleted file mode 100644 index 48fc8dca2..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/vulncheck.go +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright 2021 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 vulncheck - -import ( - "fmt" - "go/ast" - "go/token" - "go/types" - "strings" - - "golang.org/x/exp/slices" - "golang.org/x/tools/go/packages" - "golang.org/x/vuln/client" - "golang.org/x/vuln/osv" -) - -// Config is used for configuring vulncheck algorithms. -type Config struct { - // ImportsOnly instructs vulncheck to analyze import chains only. - // Otherwise, call chains are analyzed too. - ImportsOnly bool - - // Client is used for querying data from a vulnerability database. - Client client.Client - - // SourceGoVersion is Go version used to build Source inputs passed - // to vulncheck. If not provided, the current underlying Go version - // is used to detect vulnerabilities in Go standard library. - SourceGoVersion string - - // Consider only vulnerabilities that apply to this OS and architecture. - // An empty string means "all" (don't filter). - // Applies only to Source. - GOOS, GOARCH string -} - -// Package is a Go package for vulncheck analysis. It is a version of -// packages.Package trimmed down to reduce memory consumption. -type Package struct { - Name string - PkgPath string - Imports []*Package - Pkg *types.Package - Fset *token.FileSet - Syntax []*ast.File - TypesInfo *types.Info - Module *Module -} - -// Module is a Go module for vulncheck analysis. -type Module struct { - Path string - Version string - Dir string - Replace *Module -} - -// Convert transforms a slice of packages.Package to -// a slice of corresponding vulncheck.Package. -func Convert(pkgs []*packages.Package) []*Package { - convertMod := newModuleConverter() - ps := make(map[*packages.Package]*Package) - var pkg func(*packages.Package) *Package - pkg = func(p *packages.Package) *Package { - if vp, ok := ps[p]; ok { - return vp - } - - vp := &Package{ - Name: p.Name, - PkgPath: p.PkgPath, - Pkg: p.Types, - Fset: p.Fset, - Syntax: p.Syntax, - TypesInfo: p.TypesInfo, - Module: convertMod(p.Module), - } - ps[p] = vp - - for _, i := range p.Imports { - vp.Imports = append(vp.Imports, pkg(i)) - } - return vp - } - - var vpkgs []*Package - for _, p := range pkgs { - vpkgs = append(vpkgs, pkg(p)) - } - return vpkgs -} - -// Result contains information on how known vulnerabilities are reachable -// in the call graph, package imports graph, and module requires graph of -// the user code. -type Result struct { - // Calls is a call graph whose roots are program entry functions and - // methods, and sinks are known vulnerable symbols. It is empty when - // Config.ImportsOnly is true or when no vulnerable symbols are reachable - // via the program call graph. - Calls *CallGraph - - // Imports is a package dependency graph whose roots are entry user packages - // and sinks are packages with some known vulnerable symbols. It is empty - // when no packages with vulnerabilities are imported in the program. - Imports *ImportGraph - - // Requires is a module dependency graph whose roots are entry user modules - // and sinks are modules with some vulnerable packages. It is empty when no - // modules with vulnerabilities are required by the program. If used, the - // standard library is modeled as an artificial "stdlib" module whose version - // is the Go version used to build the code under analysis. - Requires *RequireGraph - - // Vulns contains information on detected vulnerabilities and their place in - // the above graphs. Only vulnerabilities whose symbols are reachable in Calls, - // or whose packages are imported in Imports, or whose modules are required in - // Requires, have an entry in Vulns. - Vulns []*Vuln - - // Modules are the modules that comprise the user code. - Modules []*Module -} - -// Vuln provides information on how a vulnerability is affecting user code by -// connecting it to the Result.{Calls,Imports,Requires} graphs. Vulnerabilities -// detected in Go binaries do not appear in the Result graphs. -type Vuln struct { - // OSV contains information on the detected vulnerability in the shared - // vulnerability format. - // - // OSV, Symbol, PkgPath, and ModPath identify a vulnerability. - // - // Note that *osv.Entry may describe multiple symbols from multiple - // packages. - OSV *osv.Entry - - // Symbol is the name of the detected vulnerable function or method. - Symbol string - - // PkgPath is the package path of the detected Symbol. - PkgPath string - - // ModPath is the module path corresponding to PkgPath. - ModPath string - - // CallSink is the ID of the FuncNode in Result.Calls corresponding to - // Symbol. - // - // When analyzing binaries, Symbol is not reachable, or Config.ImportsOnly - // is true, CallSink will be unavailable and set to 0. - CallSink int - - // ImportSink is the ID of the PkgNode in Result.Imports corresponding to - // PkgPath. - // - // When analyzing binaries or PkgPath is not imported, ImportSink will be - // unavailable and set to 0. - ImportSink int - - // RequireSink is the ID of the ModNode in Result.Requires corresponding to - // ModPath. - // - // When analyzing binaries, RequireSink will be unavailable and set to 0. - RequireSink int -} - -// CallGraph is a slice of a full program call graph whose sinks are vulnerable -// functions and sources are entry points of user packages. -// -// CallGraph is directed from vulnerable functions towards program entry -// functions (see FuncNode) for a more efficient traversal of the slice -// related to a particular vulnerability. -type CallGraph struct { - // Functions contains all call graph nodes as a map: FuncNode.ID -> FuncNode. - Functions map[int]*FuncNode - - // Entries are IDs of a subset of Functions representing vulncheck entry points. - Entries []int -} - -// A FuncNode describes a function in the call graph. -type FuncNode struct { - // ID is the id used to identify the FuncNode in CallGraph. - ID int - - // Name is the name of the function. - Name string - - // RecvType is the receiver object type of this function, if any. - RecvType string - - // PkgPath is the import path of the package containing the function. - PkgPath string - - // Position describes the position of the function in the file. - Pos *token.Position - - // CallSites is a set of call sites where this function is called. - CallSites []*CallSite -} - -func (fn *FuncNode) String() string { - if fn.RecvType == "" { - return fmt.Sprintf("%s.%s", fn.PkgPath, fn.Name) - } - return fmt.Sprintf("%s.%s", fn.RecvType, fn.Name) -} - -// A CallSite describes a function call. -type CallSite struct { - // Parent is ID of the enclosing function where the call is made. - Parent int - - // Name stands for the name of the function (variable) being called. - Name string - - // RecvType is the full path of the receiver object type, if any. - RecvType string - - // Position describes the position of the function in the file. - Pos *token.Position - - // Resolved indicates if the called function can be statically resolved. - Resolved bool -} - -// RequireGraph is a slice of a full program module requires graph whose sinks -// are modules with known vulnerabilities and sources are modules of user entry -// packages. -// -// RequireGraph is directed from a vulnerable module towards the program entry -// modules (see ModNode) for a more efficient traversal of the slice related -// to a particular vulnerability. -type RequireGraph struct { - // Modules contains all module nodes as a map: module node id -> module node. - Modules map[int]*ModNode - - // Entries are IDs of a subset of Modules representing modules of vulncheck entry points. - Entries []int -} - -// A ModNode describes a module in the requires graph. -type ModNode struct { - // ID is the id used to identify the ModNode in CallGraph. - ID int - - // Path is the module path. - Path string - - // Version is the module version. - Version string - - // Replace is the ID of the replacement module node. - // A zero value means there is no replacement. - Replace int - - // RequiredBy contains IDs of the modules requiring this module. - RequiredBy []int -} - -// ImportGraph is a slice of a full program package import graph whose sinks are -// packages with some known vulnerabilities and sources are user specified -// packages. -// -// ImportGraph is directed from a vulnerable package towards the program entry -// packages (see PkgNode) for a more efficient traversal of the slice related -// to a particular vulnerability. -type ImportGraph struct { - // Packages contains all package nodes as a map: package node id -> package node. - Packages map[int]*PkgNode - - // Entries are IDs of a subset of Packages representing packages of vulncheck entry points. - Entries []int -} - -// A PkgNode describes a package in the import graph. -type PkgNode struct { - // ID is the id used to identify the PkgNode in ImportGraph. - ID int - - // Name is the package identifier as it appears in the source code. - Name string - - // Path is the package path. - Path string - - // Module holds ID of the corresponding module (node) in the Requires graph. - Module int - - // ImportedBy contains IDs of packages directly importing this package. - ImportedBy []int - - // pkg is used for connecting package node to module and call graph nodes. - pkg *Package -} - -// moduleVulnerabilities is an internal structure for -// holding and querying vulnerabilities provided by a -// vulnerability database client. -type moduleVulnerabilities []modVulns - -// modVulns groups vulnerabilities per module. -type modVulns struct { - mod *Module - vulns []*osv.Entry -} - -func (mv moduleVulnerabilities) filter(os, arch string) moduleVulnerabilities { - var filteredMod moduleVulnerabilities - for _, mod := range mv { - module := mod.mod - modVersion := module.Version - if module.Replace != nil { - modVersion = module.Replace.Version - } - // TODO(https://golang.org/issues/49264): if modVersion == "", try vcs? - var filteredVulns []*osv.Entry - for _, v := range mod.vulns { - var filteredAffected []osv.Affected - for _, a := range v.Affected { - // Vulnerabilities from some databases might contain - // information on related but different modules that - // were, say, reported in the same CVE. We filter such - // information out as it might lead to incorrect results: - // Computing a latest fix could consider versions of these - // different packages. - if a.Package.Name != module.Path { - continue - } - - // A module version is affected if - // - it is included in one of the affected version ranges - // - and module version is not "" - if modVersion == "" { - // Module version of "" means the module version is not available, - // and so we don't want to spam users with potential false alarms. - // TODO: issue warning for "" cases above? - continue - } - if !a.Ranges.AffectsSemver(modVersion) { - continue - } - var filteredImports []osv.EcosystemSpecificImport - for _, p := range a.EcosystemSpecific.Imports { - if matchesPlatform(os, arch, p) { - filteredImports = append(filteredImports, p) - } - } - if len(a.EcosystemSpecific.Imports) != 0 && len(filteredImports) == 0 { - continue - } - a.EcosystemSpecific.Imports = filteredImports - filteredAffected = append(filteredAffected, a) - } - if len(filteredAffected) == 0 { - continue - } - // save the non-empty vulnerability with only - // affected symbols. - newV := *v - newV.Affected = filteredAffected - filteredVulns = append(filteredVulns, &newV) - } - filteredMod = append(filteredMod, modVulns{ - mod: module, - vulns: filteredVulns, - }) - } - return filteredMod -} - -func matchesPlatform(os, arch string, e osv.EcosystemSpecificImport) bool { - return matchesPlatformComponent(os, e.GOOS) && - matchesPlatformComponent(arch, e.GOARCH) -} - -// matchesPlatformComponent reports whether a GOOS (or GOARCH) -// matches a list of GOOS (or GOARCH) values from an osv.EcosystemSpecificImport. -func matchesPlatformComponent(s string, ps []string) bool { - // An empty input or an empty GOOS or GOARCH list means "matches everything." - if s == "" || len(ps) == 0 { - return true - } - for _, p := range ps { - if s == p { - return true - } - } - return false -} - -// vulnsForPackage returns the vulnerabilities for the module which is the most -// specific prefix of importPath, or nil if there is no matching module with -// vulnerabilities. -func (mv moduleVulnerabilities) vulnsForPackage(importPath string) []*osv.Entry { - isStd := isStdPackage(importPath) - var mostSpecificMod *modVulns - for _, mod := range mv { - md := mod - if isStd && mod.mod == stdlibModule { - // standard library packages do not have an associated module, - // so we relate them to the artificial stdlib module. - mostSpecificMod = &md - } else if strings.HasPrefix(importPath, md.mod.Path) { - if mostSpecificMod == nil || len(mostSpecificMod.mod.Path) < len(md.mod.Path) { - mostSpecificMod = &md - } - } - } - if mostSpecificMod == nil { - return nil - } - - if mostSpecificMod.mod.Replace != nil { - // standard libraries do not have a module nor replace module - importPath = fmt.Sprintf("%s%s", mostSpecificMod.mod.Replace.Path, strings.TrimPrefix(importPath, mostSpecificMod.mod.Path)) - } - vulns := mostSpecificMod.vulns - packageVulns := []*osv.Entry{} -Vuln: - for _, v := range vulns { - for _, a := range v.Affected { - for _, p := range a.EcosystemSpecific.Imports { - if p.Path == importPath { - packageVulns = append(packageVulns, v) - continue Vuln - } - } - } - } - return packageVulns -} - -// vulnsForSymbol returns vulnerabilities for `symbol` in `mv.VulnsForPackage(importPath)`. -func (mv moduleVulnerabilities) vulnsForSymbol(importPath, symbol string) []*osv.Entry { - vulns := mv.vulnsForPackage(importPath) - if vulns == nil { - return nil - } - - symbolVulns := []*osv.Entry{} -vulnLoop: - for _, v := range vulns { - for _, a := range v.Affected { - for _, p := range a.EcosystemSpecific.Imports { - if p.Path != importPath { - continue - } - if len(p.Symbols) > 0 && !slices.Contains(p.Symbols, symbol) { - continue - } - symbolVulns = append(symbolVulns, v) - continue vulnLoop - } - } - } - return symbolVulns -} - -func newModuleConverter() func(m *packages.Module) *Module { - pmap := map[*packages.Module]*Module{} - var convert func(m *packages.Module) *Module - convert = func(m *packages.Module) *Module { - if m == nil { - return nil - } - if vm, ok := pmap[m]; ok { - return vm - } - vm := &Module{ - Path: m.Path, - Version: m.Version, - Dir: m.Dir, - Replace: convert(m.Replace), - } - pmap[m] = vm - return vm - } - return convert -} diff --git a/vendor/golang.org/x/vuln/vulncheck/witness.go b/vendor/golang.org/x/vuln/vulncheck/witness.go deleted file mode 100644 index 75f1722fe..000000000 --- a/vendor/golang.org/x/vuln/vulncheck/witness.go +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2021 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 vulncheck - -import ( - "container/list" - "fmt" - "go/token" - "sort" - "strings" - "sync" -) - -// ImportChain is a slice of packages where each -// subsequent package is imported by its immediate -// predecessor. The chain starts with a client package -// and ends in a package with some known vulnerabilities. -type ImportChain []*PkgNode - -// ImportChains returns a slice of representative import chains for -// each vulnerability in res. The returned chains are ordered -// increasingly by their length. -// -// ImportChains performs a breadth-first search of res.RequireGraph starting -// at a vulnerable package and going up until reaching an entry package -// in res.ImportGraph.Entries. During this search, a package is visited -// only once to avoid analyzing every possible import chain. Hence, not -// all import chains are analyzed. -// -// Note that vulnerabilities from the same package will have the same -// slice of identified import chains. -func ImportChains(res *Result) map[*Vuln][]ImportChain { - // Group vulns per package. - vPerPkg := make(map[int][]*Vuln) - for _, v := range res.Vulns { - vPerPkg[v.ImportSink] = append(vPerPkg[v.ImportSink], v) - } - - // Collect chains in parallel for every package path. - var wg sync.WaitGroup - var mu sync.Mutex - chains := make(map[*Vuln][]ImportChain) - for pkgID, vulns := range vPerPkg { - pID := pkgID - vs := vulns - wg.Add(1) - go func() { - pChains := importChains(pID, res) - mu.Lock() - for _, v := range vs { - chains[v] = pChains - } - mu.Unlock() - wg.Done() - }() - } - wg.Wait() - return chains -} - -// importChains finds representative chains of package imports -// leading to vulnerable package identified with vulnSinkID. -func importChains(vulnSinkID int, res *Result) []ImportChain { - if vulnSinkID == 0 { - return nil - } - - // Entry packages, needed for finalizing chains. - entries := make(map[int]bool) - for _, e := range res.Imports.Entries { - entries[e] = true - } - - var chains []ImportChain - seen := make(map[int]bool) - - queue := list.New() - queue.PushBack(&importChain{pkg: res.Imports.Packages[vulnSinkID]}) - for queue.Len() > 0 { - front := queue.Front() - c := front.Value.(*importChain) - queue.Remove(front) - - pkg := c.pkg - if seen[pkg.ID] { - continue - } - seen[pkg.ID] = true - - for _, impBy := range pkg.ImportedBy { - imp := res.Imports.Packages[impBy] - newC := &importChain{pkg: imp, child: c} - // If the next package is an entry, we have - // a chain to report. - if entries[imp.ID] { - chains = append(chains, newC.ImportChain()) - } - queue.PushBack(newC) - } - } - return chains -} - -// importChain models an chain of package imports. -type importChain struct { - pkg *PkgNode - child *importChain -} - -// ImportChain converts importChain to ImportChain type. -func (r *importChain) ImportChain() ImportChain { - if r == nil { - return nil - } - return append([]*PkgNode{r.pkg}, r.child.ImportChain()...) -} - -// CallStack is a call stack starting with a client -// function or method and ending with a call to a -// vulnerable symbol. -type CallStack []StackEntry - -// StackEntry is an element of a call stack. -type StackEntry struct { - // Function whose frame is on the stack. - Function *FuncNode - - // Call is the call site inducing the stack frame. - // nil when the frame represents the stack entry point. - Call *CallSite -} - -// CallStacks returns representative call stacks for each -// vulnerability in res. The returned call stacks are heuristically -// ordered by how seemingly easy is to understand them: shorter -// call stacks with less dynamic call sites appear earlier in the -// returned slices. -// -// CallStacks performs a breadth-first search of res.CallGraph starting -// at the vulnerable symbol and going up until reaching an entry -// function or method in res.CallGraph.Entries. During this search, -// each function is visited at most once to avoid potential -// exponential explosion. Hence, not all call stacks are analyzed. -func CallStacks(res *Result) map[*Vuln][]CallStack { - var ( - wg sync.WaitGroup - mu sync.Mutex - ) - stacksPerVuln := make(map[*Vuln][]CallStack) - for _, vuln := range res.Vulns { - vuln := vuln - wg.Add(1) - go func() { - cs := callStacks(vuln.CallSink, res) - // sort call stacks by the estimated value to the user - sort.SliceStable(cs, func(i int, j int) bool { return stackLess(cs[i], cs[j]) }) - mu.Lock() - stacksPerVuln[vuln] = cs - mu.Unlock() - wg.Done() - }() - } - - wg.Wait() - return stacksPerVuln -} - -// callStacks finds representative call stacks -// for vulnerable symbol identified with vulnSinkID. -func callStacks(vulnSinkID int, res *Result) []CallStack { - if vulnSinkID == 0 { - return nil - } - - entries := make(map[int]bool) - for _, e := range res.Calls.Entries { - entries[e] = true - } - - var stacks []CallStack - seen := make(map[int]bool) - - queue := list.New() - queue.PushBack(&callChain{f: res.Calls.Functions[vulnSinkID]}) - - for queue.Len() > 0 { - front := queue.Front() - c := front.Value.(*callChain) - queue.Remove(front) - - f := c.f - if seen[f.ID] { - continue - } - seen[f.ID] = true - - // Pick a single call site for each function in determinstic order. - // A single call site is sufficient as we visit a function only once. - for _, cs := range callsites(f.CallSites, res, seen) { - callee := res.Calls.Functions[cs.Parent] - nStack := &callChain{f: callee, call: cs, child: c} - if entries[callee.ID] { - stacks = append(stacks, nStack.CallStack()) - } - queue.PushBack(nStack) - } - } - return stacks -} - -// callsites picks a call site from sites for each non-visited function. -// For each such function, the smallest (posLess) call site is chosen. The -// returned slice is sorted by caller functions (funcLess). Assumes callee -// of each call site is the same. -func callsites(sites []*CallSite, result *Result, visited map[int]bool) []*CallSite { - minCs := make(map[int]*CallSite) - for _, cs := range sites { - if visited[cs.Parent] { - continue - } - if csLess(cs, minCs[cs.Parent]) { - minCs[cs.Parent] = cs - } - } - - var fs []*FuncNode - for id := range minCs { - fs = append(fs, result.Calls.Functions[id]) - } - sort.SliceStable(fs, func(i, j int) bool { return funcLess(fs[i], fs[j]) }) - - var css []*CallSite - for _, f := range fs { - css = append(css, minCs[f.ID]) - } - return css -} - -// callChain models a chain of function calls. -type callChain struct { - call *CallSite // nil for entry points - f *FuncNode - child *callChain -} - -// CallStack converts callChain to CallStack type. -func (c *callChain) CallStack() CallStack { - if c == nil { - return nil - } - return append(CallStack{StackEntry{Function: c.f, Call: c.call}}, c.child.CallStack()...) -} - -// weight computes an approximate measure of how easy is to understand the call -// stack when presented to the client as a witness. The smaller the value, the more -// understandable the stack is. Currently defined as the number of unresolved -// call sites in the stack. -func weight(stack CallStack) int { - w := 0 - for _, e := range stack { - if e.Call != nil && !e.Call.Resolved { - w += 1 - } - } - return w -} - -func isStdPackage(pkg string) bool { - if pkg == "" { - return false - } - // std packages do not have a "." in their path. For instance, see - // Contains in pkgsite/+/refs/heads/master/internal/stdlbib/stdlib.go. - if i := strings.IndexByte(pkg, '/'); i != -1 { - pkg = pkg[:i] - } - return !strings.Contains(pkg, ".") -} - -// confidence computes an approximate measure of whether the stack -// is realizeable in practice. Currently, it equals the number of call -// sites in stack that go through standard libraries. Such call stacks -// have been experimentally shown to often result in false positives. -func confidence(stack CallStack) int { - c := 0 - for _, e := range stack { - if isStdPackage(e.Function.PkgPath) { - c += 1 - } - } - return c -} - -// stackLess compares two call stacks in terms of their estimated -// value to the user. Shorter stacks generally come earlier in the ordering. -// -// Two stacks are lexicographically ordered by: -// 1) their estimated level of confidence in being a real call stack, -// 2) their length, and 3) the number of dynamic call sites in the stack. -func stackLess(s1, s2 CallStack) bool { - if c1, c2 := confidence(s1), confidence(s2); c1 != c2 { - return c1 < c2 - } - - if len(s1) != len(s2) { - return len(s1) < len(s2) - } - - if w1, w2 := weight(s1), weight(s2); w1 != w2 { - return w1 < w2 - } - - // At this point, the stableness/determinism of - // sorting is guaranteed by the determinism of - // the underlying call graph and the call stack - // search algorithm. - return true -} - -// csLess compares two call sites by their locations and, if needed, -// their string representation. -func csLess(cs1, cs2 *CallSite) bool { - if cs2 == nil { - return true - } - - // fast code path - if p1, p2 := cs1.Pos, cs2.Pos; p1 != nil && p2 != nil { - if posLess(*p1, *p2) { - return true - } - if posLess(*p2, *p1) { - return false - } - // for sanity, should not occur in practice - return fmt.Sprintf("%v.%v", cs1.RecvType, cs2.Name) < fmt.Sprintf("%v.%v", cs2.RecvType, cs2.Name) - } - - // code path rarely exercised - if cs2.Pos == nil { - return true - } - if cs1.Pos == nil { - return false - } - // should very rarely occur in practice - return fmt.Sprintf("%v.%v", cs1.RecvType, cs2.Name) < fmt.Sprintf("%v.%v", cs2.RecvType, cs2.Name) -} - -// posLess compares two positions by their line and column number, -// and filename if needed. -func posLess(p1, p2 token.Position) bool { - if p1.Line < p2.Line { - return true - } - if p2.Line < p1.Line { - return false - } - - if p1.Column < p2.Column { - return true - } - if p2.Column < p1.Column { - return false - } - - return strings.Compare(p1.Filename, p2.Filename) == -1 -} - -// funcLess compares two function nodes by locations of -// corresponding functions and, if needed, their string representation. -func funcLess(f1, f2 *FuncNode) bool { - if p1, p2 := f1.Pos, f2.Pos; p1 != nil && p2 != nil { - if posLess(*p1, *p2) { - return true - } - if posLess(*p2, *p1) { - return false - } - // for sanity, should not occur in practice - return f1.String() < f2.String() - } - - if f2.Pos == nil { - return true - } - if f1.Pos == nil { - return false - } - // should happen only for inits - return f1.String() < f2.String() -} diff --git a/vendor/modules.txt b/vendor/modules.txt index da339510a..fdac66d58 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -798,13 +798,12 @@ golang.org/x/crypto/blake2b # golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e ## explicit; go 1.18 golang.org/x/exp/constraints -golang.org/x/exp/maps golang.org/x/exp/slices # golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 ## explicit; go 1.18 golang.org/x/exp/typeparams -# golang.org/x/mod v0.10.0 -## explicit; go 1.17 +# golang.org/x/mod v0.14.0 +## explicit; go 1.18 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module @@ -818,14 +817,13 @@ golang.org/x/net/idna golang.org/x/net/internal/timeseries golang.org/x/net/publicsuffix golang.org/x/net/trace -# golang.org/x/sync v0.4.0 -## explicit; go 1.17 +# golang.org/x/sync v0.6.0 +## explicit; go 1.18 golang.org/x/sync/errgroup golang.org/x/sync/semaphore # golang.org/x/sys v0.16.0 ## explicit; go 1.18 golang.org/x/sys/cpu -golang.org/x/sys/execabs golang.org/x/sys/unix golang.org/x/sys/windows # golang.org/x/text v0.14.0 @@ -841,7 +839,7 @@ golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width -# golang.org/x/tools v0.8.0 +# golang.org/x/tools v0.17.0 ## explicit; go 1.18 golang.org/x/tools/cover golang.org/x/tools/go/analysis @@ -905,11 +903,12 @@ golang.org/x/tools/go/ssa/ssautil golang.org/x/tools/go/types/objectpath golang.org/x/tools/go/types/typeutil golang.org/x/tools/imports +golang.org/x/tools/internal/analysisinternal golang.org/x/tools/internal/event golang.org/x/tools/internal/event/core golang.org/x/tools/internal/event/keys golang.org/x/tools/internal/event/label -golang.org/x/tools/internal/fastwalk +golang.org/x/tools/internal/event/tag golang.org/x/tools/internal/gcimporter golang.org/x/tools/internal/gocommand golang.org/x/tools/internal/gopathwalk @@ -919,18 +918,22 @@ golang.org/x/tools/internal/pkgbits golang.org/x/tools/internal/tokeninternal golang.org/x/tools/internal/typeparams golang.org/x/tools/internal/typesinternal -# golang.org/x/vuln v0.0.0-20220922014440-c4543efbee9e +golang.org/x/tools/internal/versions +# golang.org/x/vuln v1.0.4 ## explicit; go 1.18 -golang.org/x/vuln/client golang.org/x/vuln/cmd/govulncheck -golang.org/x/vuln/cmd/govulncheck/internal/govulncheck golang.org/x/vuln/internal +golang.org/x/vuln/internal/buildinfo +golang.org/x/vuln/internal/client golang.org/x/vuln/internal/derrors +golang.org/x/vuln/internal/gosym +golang.org/x/vuln/internal/govulncheck +golang.org/x/vuln/internal/osv +golang.org/x/vuln/internal/scan golang.org/x/vuln/internal/semver -golang.org/x/vuln/osv -golang.org/x/vuln/vulncheck -golang.org/x/vuln/vulncheck/internal/binscan -golang.org/x/vuln/vulncheck/internal/gosym +golang.org/x/vuln/internal/vulncheck +golang.org/x/vuln/internal/web +golang.org/x/vuln/scan # golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df ## explicit; go 1.17 golang.org/x/xerrors @@ -1088,7 +1091,7 @@ mvdan.cc/interfacer/check # mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b ## explicit mvdan.cc/lint -# mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d -## explicit; go 1.18 +# mvdan.cc/unparam v0.0.0-20230312165513-e84e2d14e3b8 +## explicit; go 1.19 mvdan.cc/unparam/check # github.com/asaskevich/govalidator => github.com/pieceofsoul/govalidator v0.0.0-20230607103513-8dce951b10b8 From e15a8d900c9f9914840b253311504e6e8bf97586 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:42:14 +0200 Subject: [PATCH 28/31] gomod: Update google.golang.org/grpc --- go.mod | 4 +- go.sum | 12 +- .../golang/protobuf/jsonpb/decode.go | 530 ----------------- .../golang/protobuf/jsonpb/encode.go | 559 ------------------ .../github.com/golang/protobuf/jsonpb/json.go | 69 --- .../github.com/golang/protobuf/ptypes/any.go | 179 ------ .../golang/protobuf/ptypes/any/any.pb.go | 62 -- .../github.com/golang/protobuf/ptypes/doc.go | 10 - .../golang/protobuf/ptypes/duration.go | 76 --- .../protobuf/ptypes/duration/duration.pb.go | 63 -- .../golang/protobuf/ptypes/timestamp.go | 112 ---- .../protobuf/ptypes/timestamp/timestamp.pb.go | 64 -- .../grpc_binarylog_v1/binarylog.pb.go | 6 +- vendor/google.golang.org/grpc/clientconn.go | 26 +- .../grpc/encoding/proto/proto.go | 24 +- .../grpc/internal/binarylog/method_logger.go | 9 +- .../grpc/internal/binarylog/sink.go | 2 +- .../grpc/internal/grpcrand/grpcrand.go | 5 + .../grpc/internal/grpcrand/grpcrand_go1.21.go | 73 +++ .../grpc/internal/internal.go | 20 +- .../grpc/internal/pretty/pretty.go | 7 +- .../grpc/internal/resolver/unix/unix.go | 4 + .../grpc/internal/status/status.go | 15 +- ...ive_nonunix.go => tcp_keepalive_others.go} | 2 +- .../grpc/internal/tcp_keepalive_windows.go | 54 ++ .../grpc/internal/transport/controlbuf.go | 5 +- .../grpc/internal/transport/handler_server.go | 2 +- .../grpc/internal/transport/http2_client.go | 18 +- .../grpc/internal/transport/http2_server.go | 36 +- .../grpc/internal/transport/transport.go | 9 +- .../grpc/metadata/metadata.go | 13 +- .../grpc/resolver/resolver.go | 13 + .../grpc/resolver_wrapper.go | 1 + vendor/google.golang.org/grpc/rpc_util.go | 77 ++- vendor/google.golang.org/grpc/server.go | 64 +- vendor/google.golang.org/grpc/stream.go | 9 +- vendor/google.golang.org/grpc/trace.go | 26 +- .../google.golang.org/grpc/trace_notrace.go | 52 ++ .../google.golang.org/grpc/trace_withtrace.go | 39 ++ vendor/google.golang.org/grpc/version.go | 2 +- vendor/google.golang.org/grpc/vet.sh | 10 +- .../protobuf/protoadapt/convert.go | 31 + vendor/modules.txt | 10 +- 43 files changed, 532 insertions(+), 1872 deletions(-) delete mode 100644 vendor/github.com/golang/protobuf/jsonpb/decode.go delete mode 100644 vendor/github.com/golang/protobuf/jsonpb/encode.go delete mode 100644 vendor/github.com/golang/protobuf/jsonpb/json.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/any.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/any/any.pb.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/doc.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/duration.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp.go delete mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go create mode 100644 vendor/google.golang.org/grpc/internal/grpcrand/grpcrand_go1.21.go rename vendor/google.golang.org/grpc/internal/{tcp_keepalive_nonunix.go => tcp_keepalive_others.go} (96%) create mode 100644 vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go create mode 100644 vendor/google.golang.org/grpc/trace_notrace.go create mode 100644 vendor/google.golang.org/grpc/trace_withtrace.go create mode 100644 vendor/google.golang.org/protobuf/protoadapt/convert.go diff --git a/go.mod b/go.mod index fd3fbaa19..c3550906f 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/zenazn/goji v1.0.1 golang.org/x/text v0.14.0 golang.org/x/vuln v1.0.4 - google.golang.org/grpc v1.60.1 + google.golang.org/grpc v1.62.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 google.golang.org/protobuf v1.33.0 ) @@ -216,7 +216,7 @@ require ( golang.org/x/sys v0.16.0 // indirect golang.org/x/tools v0.17.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 896326eb2..df9f401f2 100644 --- a/go.sum +++ b/go.sum @@ -29,8 +29,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf 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/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -1097,8 +1097,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 h1:6GQBEOdGkX6MMTLT9V+TjtIRZCw9VPD5Z+yHY9wMgS0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= 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= @@ -1116,8 +1116,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= diff --git a/vendor/github.com/golang/protobuf/jsonpb/decode.go b/vendor/github.com/golang/protobuf/jsonpb/decode.go deleted file mode 100644 index 6c16c255f..000000000 --- a/vendor/github.com/golang/protobuf/jsonpb/decode.go +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonpb - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "math" - "reflect" - "strconv" - "strings" - "time" - - "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/encoding/protojson" - protoV2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -const wrapJSONUnmarshalV2 = false - -// UnmarshalNext unmarshals the next JSON object from d into m. -func UnmarshalNext(d *json.Decoder, m proto.Message) error { - return new(Unmarshaler).UnmarshalNext(d, m) -} - -// Unmarshal unmarshals a JSON object from r into m. -func Unmarshal(r io.Reader, m proto.Message) error { - return new(Unmarshaler).Unmarshal(r, m) -} - -// UnmarshalString unmarshals a JSON object from s into m. -func UnmarshalString(s string, m proto.Message) error { - return new(Unmarshaler).Unmarshal(strings.NewReader(s), m) -} - -// Unmarshaler is a configurable object for converting from a JSON -// representation to a protocol buffer object. -type Unmarshaler struct { - // AllowUnknownFields specifies whether to allow messages to contain - // unknown JSON fields, as opposed to failing to unmarshal. - AllowUnknownFields bool - - // AnyResolver is used to resolve the google.protobuf.Any well-known type. - // If unset, the global registry is used by default. - AnyResolver AnyResolver -} - -// JSONPBUnmarshaler is implemented by protobuf messages that customize the way -// they are unmarshaled from JSON. Messages that implement this should also -// implement JSONPBMarshaler so that the custom format can be produced. -// -// The JSON unmarshaling must follow the JSON to proto specification: -// https://developers.google.com/protocol-buffers/docs/proto3#json -// -// Deprecated: Custom types should implement protobuf reflection instead. -type JSONPBUnmarshaler interface { - UnmarshalJSONPB(*Unmarshaler, []byte) error -} - -// Unmarshal unmarshals a JSON object from r into m. -func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error { - return u.UnmarshalNext(json.NewDecoder(r), m) -} - -// UnmarshalNext unmarshals the next JSON object from d into m. -func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error { - if m == nil { - return errors.New("invalid nil message") - } - - // Parse the next JSON object from the stream. - raw := json.RawMessage{} - if err := d.Decode(&raw); err != nil { - return err - } - - // Check for custom unmarshalers first since they may not properly - // implement protobuf reflection that the logic below relies on. - if jsu, ok := m.(JSONPBUnmarshaler); ok { - return jsu.UnmarshalJSONPB(u, raw) - } - - mr := proto.MessageReflect(m) - - // NOTE: For historical reasons, a top-level null is treated as a noop. - // This is incorrect, but kept for compatibility. - if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" { - return nil - } - - if wrapJSONUnmarshalV2 { - // NOTE: If input message is non-empty, we need to preserve merge semantics - // of the old jsonpb implementation. These semantics are not supported by - // the protobuf JSON specification. - isEmpty := true - mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool { - isEmpty = false // at least one iteration implies non-empty - return false - }) - if !isEmpty { - // Perform unmarshaling into a newly allocated, empty message. - mr = mr.New() - - // Use a defer to copy all unmarshaled fields into the original message. - dst := proto.MessageReflect(m) - defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - dst.Set(fd, v) - return true - }) - } - - // Unmarshal using the v2 JSON unmarshaler. - opts := protojson.UnmarshalOptions{ - DiscardUnknown: u.AllowUnknownFields, - } - if u.AnyResolver != nil { - opts.Resolver = anyResolver{u.AnyResolver} - } - return opts.Unmarshal(raw, mr.Interface()) - } else { - if err := u.unmarshalMessage(mr, raw); err != nil { - return err - } - return protoV2.CheckInitialized(mr.Interface()) - } -} - -func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error { - md := m.Descriptor() - fds := md.Fields() - - if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok { - return jsu.UnmarshalJSONPB(u, in) - } - - if string(in) == "null" && md.FullName() != "google.protobuf.Value" { - return nil - } - - switch wellKnownType(md.FullName()) { - case "Any": - var jsonObject map[string]json.RawMessage - if err := json.Unmarshal(in, &jsonObject); err != nil { - return err - } - - rawTypeURL, ok := jsonObject["@type"] - if !ok { - return errors.New("Any JSON doesn't have '@type'") - } - typeURL, err := unquoteString(string(rawTypeURL)) - if err != nil { - return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL) - } - m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL)) - - var m2 protoreflect.Message - if u.AnyResolver != nil { - mi, err := u.AnyResolver.Resolve(typeURL) - if err != nil { - return err - } - m2 = proto.MessageReflect(mi) - } else { - mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL) - if err != nil { - if err == protoregistry.NotFound { - return fmt.Errorf("could not resolve Any message type: %v", typeURL) - } - return err - } - m2 = mt.New() - } - - if wellKnownType(m2.Descriptor().FullName()) != "" { - rawValue, ok := jsonObject["value"] - if !ok { - return errors.New("Any JSON doesn't have 'value'") - } - if err := u.unmarshalMessage(m2, rawValue); err != nil { - return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err) - } - } else { - delete(jsonObject, "@type") - rawJSON, err := json.Marshal(jsonObject) - if err != nil { - return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err) - } - if err = u.unmarshalMessage(m2, rawJSON); err != nil { - return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err) - } - } - - rawWire, err := protoV2.Marshal(m2.Interface()) - if err != nil { - return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err) - } - m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire)) - return nil - case "BoolValue", "BytesValue", "StringValue", - "Int32Value", "UInt32Value", "FloatValue", - "Int64Value", "UInt64Value", "DoubleValue": - fd := fds.ByNumber(1) - v, err := u.unmarshalValue(m.NewField(fd), in, fd) - if err != nil { - return err - } - m.Set(fd, v) - return nil - case "Duration": - v, err := unquoteString(string(in)) - if err != nil { - return err - } - d, err := time.ParseDuration(v) - if err != nil { - return fmt.Errorf("bad Duration: %v", err) - } - - sec := d.Nanoseconds() / 1e9 - nsec := d.Nanoseconds() % 1e9 - m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec))) - m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec))) - return nil - case "Timestamp": - v, err := unquoteString(string(in)) - if err != nil { - return err - } - t, err := time.Parse(time.RFC3339Nano, v) - if err != nil { - return fmt.Errorf("bad Timestamp: %v", err) - } - - sec := t.Unix() - nsec := t.Nanosecond() - m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec))) - m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec))) - return nil - case "Value": - switch { - case string(in) == "null": - m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0)) - case string(in) == "true": - m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true)) - case string(in) == "false": - m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false)) - case hasPrefixAndSuffix('"', in, '"'): - s, err := unquoteString(string(in)) - if err != nil { - return fmt.Errorf("unrecognized type for Value %q", in) - } - m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s)) - case hasPrefixAndSuffix('[', in, ']'): - v := m.Mutable(fds.ByNumber(6)) - return u.unmarshalMessage(v.Message(), in) - case hasPrefixAndSuffix('{', in, '}'): - v := m.Mutable(fds.ByNumber(5)) - return u.unmarshalMessage(v.Message(), in) - default: - f, err := strconv.ParseFloat(string(in), 0) - if err != nil { - return fmt.Errorf("unrecognized type for Value %q", in) - } - m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f)) - } - return nil - case "ListValue": - var jsonArray []json.RawMessage - if err := json.Unmarshal(in, &jsonArray); err != nil { - return fmt.Errorf("bad ListValue: %v", err) - } - - lv := m.Mutable(fds.ByNumber(1)).List() - for _, raw := range jsonArray { - ve := lv.NewElement() - if err := u.unmarshalMessage(ve.Message(), raw); err != nil { - return err - } - lv.Append(ve) - } - return nil - case "Struct": - var jsonObject map[string]json.RawMessage - if err := json.Unmarshal(in, &jsonObject); err != nil { - return fmt.Errorf("bad StructValue: %v", err) - } - - mv := m.Mutable(fds.ByNumber(1)).Map() - for key, raw := range jsonObject { - kv := protoreflect.ValueOf(key).MapKey() - vv := mv.NewValue() - if err := u.unmarshalMessage(vv.Message(), raw); err != nil { - return fmt.Errorf("bad value in StructValue for key %q: %v", key, err) - } - mv.Set(kv, vv) - } - return nil - } - - var jsonObject map[string]json.RawMessage - if err := json.Unmarshal(in, &jsonObject); err != nil { - return err - } - - // Handle known fields. - for i := 0; i < fds.Len(); i++ { - fd := fds.Get(i) - if fd.IsWeak() && fd.Message().IsPlaceholder() { - continue // weak reference is not linked in - } - - // Search for any raw JSON value associated with this field. - var raw json.RawMessage - name := string(fd.Name()) - if fd.Kind() == protoreflect.GroupKind { - name = string(fd.Message().Name()) - } - if v, ok := jsonObject[name]; ok { - delete(jsonObject, name) - raw = v - } - name = string(fd.JSONName()) - if v, ok := jsonObject[name]; ok { - delete(jsonObject, name) - raw = v - } - - field := m.NewField(fd) - // Unmarshal the field value. - if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) { - continue - } - v, err := u.unmarshalValue(field, raw, fd) - if err != nil { - return err - } - m.Set(fd, v) - } - - // Handle extension fields. - for name, raw := range jsonObject { - if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") { - continue - } - - // Resolve the extension field by name. - xname := protoreflect.FullName(name[len("[") : len(name)-len("]")]) - xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname) - if xt == nil && isMessageSet(md) { - xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension")) - } - if xt == nil { - continue - } - delete(jsonObject, name) - fd := xt.TypeDescriptor() - if fd.ContainingMessage().FullName() != m.Descriptor().FullName() { - return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName()) - } - - field := m.NewField(fd) - // Unmarshal the field value. - if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) { - continue - } - v, err := u.unmarshalValue(field, raw, fd) - if err != nil { - return err - } - m.Set(fd, v) - } - - if !u.AllowUnknownFields && len(jsonObject) > 0 { - for name := range jsonObject { - return fmt.Errorf("unknown field %q in %v", name, md.FullName()) - } - } - return nil -} - -func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool { - if fd.Cardinality() == protoreflect.Repeated { - return false - } - if md := fd.Message(); md != nil { - return md.FullName() == "google.protobuf.Value" - } - if ed := fd.Enum(); ed != nil { - return ed.FullName() == "google.protobuf.NullValue" - } - return false -} - -func isSingularJSONPBUnmarshaler(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool { - if fd.Message() != nil && fd.Cardinality() != protoreflect.Repeated { - _, ok := proto.MessageV1(v.Interface()).(JSONPBUnmarshaler) - return ok - } - return false -} - -func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { - switch { - case fd.IsList(): - var jsonArray []json.RawMessage - if err := json.Unmarshal(in, &jsonArray); err != nil { - return v, err - } - lv := v.List() - for _, raw := range jsonArray { - ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd) - if err != nil { - return v, err - } - lv.Append(ve) - } - return v, nil - case fd.IsMap(): - var jsonObject map[string]json.RawMessage - if err := json.Unmarshal(in, &jsonObject); err != nil { - return v, err - } - kfd := fd.MapKey() - vfd := fd.MapValue() - mv := v.Map() - for key, raw := range jsonObject { - var kv protoreflect.MapKey - if kfd.Kind() == protoreflect.StringKind { - kv = protoreflect.ValueOf(key).MapKey() - } else { - v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd) - if err != nil { - return v, err - } - kv = v.MapKey() - } - - vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd) - if err != nil { - return v, err - } - mv.Set(kv, vv) - } - return v, nil - default: - return u.unmarshalSingularValue(v, in, fd) - } -} - -var nonFinite = map[string]float64{ - `"NaN"`: math.NaN(), - `"Infinity"`: math.Inf(+1), - `"-Infinity"`: math.Inf(-1), -} - -func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { - switch fd.Kind() { - case protoreflect.BoolKind: - return unmarshalValue(in, new(bool)) - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - return unmarshalValue(trimQuote(in), new(int32)) - case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - return unmarshalValue(trimQuote(in), new(int64)) - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - return unmarshalValue(trimQuote(in), new(uint32)) - case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - return unmarshalValue(trimQuote(in), new(uint64)) - case protoreflect.FloatKind: - if f, ok := nonFinite[string(in)]; ok { - return protoreflect.ValueOfFloat32(float32(f)), nil - } - return unmarshalValue(trimQuote(in), new(float32)) - case protoreflect.DoubleKind: - if f, ok := nonFinite[string(in)]; ok { - return protoreflect.ValueOfFloat64(float64(f)), nil - } - return unmarshalValue(trimQuote(in), new(float64)) - case protoreflect.StringKind: - return unmarshalValue(in, new(string)) - case protoreflect.BytesKind: - return unmarshalValue(in, new([]byte)) - case protoreflect.EnumKind: - if hasPrefixAndSuffix('"', in, '"') { - vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in))) - if vd == nil { - return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName()) - } - return protoreflect.ValueOfEnum(vd.Number()), nil - } - return unmarshalValue(in, new(protoreflect.EnumNumber)) - case protoreflect.MessageKind, protoreflect.GroupKind: - err := u.unmarshalMessage(v.Message(), in) - return v, err - default: - panic(fmt.Sprintf("invalid kind %v", fd.Kind())) - } -} - -func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) { - err := json.Unmarshal(in, v) - return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err -} - -func unquoteString(in string) (out string, err error) { - err = json.Unmarshal([]byte(in), &out) - return out, err -} - -func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool { - if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix { - return true - } - return false -} - -// trimQuote is like unquoteString but simply strips surrounding quotes. -// This is incorrect, but is behavior done by the legacy implementation. -func trimQuote(in []byte) []byte { - if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' { - in = in[1 : len(in)-1] - } - return in -} diff --git a/vendor/github.com/golang/protobuf/jsonpb/encode.go b/vendor/github.com/golang/protobuf/jsonpb/encode.go deleted file mode 100644 index 685c80a62..000000000 --- a/vendor/github.com/golang/protobuf/jsonpb/encode.go +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package jsonpb - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "math" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/encoding/protojson" - protoV2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -const wrapJSONMarshalV2 = false - -// Marshaler is a configurable object for marshaling protocol buffer messages -// to the specified JSON representation. -type Marshaler struct { - // OrigName specifies whether to use the original protobuf name for fields. - OrigName bool - - // EnumsAsInts specifies whether to render enum values as integers, - // as opposed to string values. - EnumsAsInts bool - - // EmitDefaults specifies whether to render fields with zero values. - EmitDefaults bool - - // Indent controls whether the output is compact or not. - // If empty, the output is compact JSON. Otherwise, every JSON object - // entry and JSON array value will be on its own line. - // Each line will be preceded by repeated copies of Indent, where the - // number of copies is the current indentation depth. - Indent string - - // AnyResolver is used to resolve the google.protobuf.Any well-known type. - // If unset, the global registry is used by default. - AnyResolver AnyResolver -} - -// JSONPBMarshaler is implemented by protobuf messages that customize the -// way they are marshaled to JSON. Messages that implement this should also -// implement JSONPBUnmarshaler so that the custom format can be parsed. -// -// The JSON marshaling must follow the proto to JSON specification: -// https://developers.google.com/protocol-buffers/docs/proto3#json -// -// Deprecated: Custom types should implement protobuf reflection instead. -type JSONPBMarshaler interface { - MarshalJSONPB(*Marshaler) ([]byte, error) -} - -// Marshal serializes a protobuf message as JSON into w. -func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error { - b, err := jm.marshal(m) - if len(b) > 0 { - if _, err := w.Write(b); err != nil { - return err - } - } - return err -} - -// MarshalToString serializes a protobuf message as JSON in string form. -func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) { - b, err := jm.marshal(m) - if err != nil { - return "", err - } - return string(b), nil -} - -func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) { - v := reflect.ValueOf(m) - if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) { - return nil, errors.New("Marshal called with nil") - } - - // Check for custom marshalers first since they may not properly - // implement protobuf reflection that the logic below relies on. - if jsm, ok := m.(JSONPBMarshaler); ok { - return jsm.MarshalJSONPB(jm) - } - - if wrapJSONMarshalV2 { - opts := protojson.MarshalOptions{ - UseProtoNames: jm.OrigName, - UseEnumNumbers: jm.EnumsAsInts, - EmitUnpopulated: jm.EmitDefaults, - Indent: jm.Indent, - } - if jm.AnyResolver != nil { - opts.Resolver = anyResolver{jm.AnyResolver} - } - return opts.Marshal(proto.MessageReflect(m).Interface()) - } else { - // Check for unpopulated required fields first. - m2 := proto.MessageReflect(m) - if err := protoV2.CheckInitialized(m2.Interface()); err != nil { - return nil, err - } - - w := jsonWriter{Marshaler: jm} - err := w.marshalMessage(m2, "", "") - return w.buf, err - } -} - -type jsonWriter struct { - *Marshaler - buf []byte -} - -func (w *jsonWriter) write(s string) { - w.buf = append(w.buf, s...) -} - -func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error { - if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok { - b, err := jsm.MarshalJSONPB(w.Marshaler) - if err != nil { - return err - } - if typeURL != "" { - // we are marshaling this object to an Any type - var js map[string]*json.RawMessage - if err = json.Unmarshal(b, &js); err != nil { - return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err) - } - turl, err := json.Marshal(typeURL) - if err != nil { - return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err) - } - js["@type"] = (*json.RawMessage)(&turl) - if b, err = json.Marshal(js); err != nil { - return err - } - } - w.write(string(b)) - return nil - } - - md := m.Descriptor() - fds := md.Fields() - - // Handle well-known types. - const secondInNanos = int64(time.Second / time.Nanosecond) - switch wellKnownType(md.FullName()) { - case "Any": - return w.marshalAny(m, indent) - case "BoolValue", "BytesValue", "StringValue", - "Int32Value", "UInt32Value", "FloatValue", - "Int64Value", "UInt64Value", "DoubleValue": - fd := fds.ByNumber(1) - return w.marshalValue(fd, m.Get(fd), indent) - case "Duration": - const maxSecondsInDuration = 315576000000 - // "Generated output always contains 0, 3, 6, or 9 fractional digits, - // depending on required precision." - s := m.Get(fds.ByNumber(1)).Int() - ns := m.Get(fds.ByNumber(2)).Int() - if s < -maxSecondsInDuration || s > maxSecondsInDuration { - return fmt.Errorf("seconds out of range %v", s) - } - if ns <= -secondInNanos || ns >= secondInNanos { - return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos) - } - if (s > 0 && ns < 0) || (s < 0 && ns > 0) { - return errors.New("signs of seconds and nanos do not match") - } - var sign string - if s < 0 || ns < 0 { - sign, s, ns = "-", -1*s, -1*ns - } - x := fmt.Sprintf("%s%d.%09d", sign, s, ns) - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, ".000") - w.write(fmt.Sprintf(`"%vs"`, x)) - return nil - case "Timestamp": - // "RFC 3339, where generated output will always be Z-normalized - // and uses 0, 3, 6 or 9 fractional digits." - s := m.Get(fds.ByNumber(1)).Int() - ns := m.Get(fds.ByNumber(2)).Int() - if ns < 0 || ns >= secondInNanos { - return fmt.Errorf("ns out of range [0, %v)", secondInNanos) - } - t := time.Unix(s, ns).UTC() - // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits). - x := t.Format("2006-01-02T15:04:05.000000000") - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, ".000") - w.write(fmt.Sprintf(`"%vZ"`, x)) - return nil - case "Value": - // JSON value; which is a null, number, string, bool, object, or array. - od := md.Oneofs().Get(0) - fd := m.WhichOneof(od) - if fd == nil { - return errors.New("nil Value") - } - return w.marshalValue(fd, m.Get(fd), indent) - case "Struct", "ListValue": - // JSON object or array. - fd := fds.ByNumber(1) - return w.marshalValue(fd, m.Get(fd), indent) - } - - w.write("{") - if w.Indent != "" { - w.write("\n") - } - - firstField := true - if typeURL != "" { - if err := w.marshalTypeURL(indent, typeURL); err != nil { - return err - } - firstField = false - } - - for i := 0; i < fds.Len(); { - fd := fds.Get(i) - if od := fd.ContainingOneof(); od != nil { - fd = m.WhichOneof(od) - i += od.Fields().Len() - if fd == nil { - continue - } - } else { - i++ - } - - v := m.Get(fd) - - if !m.Has(fd) { - if !w.EmitDefaults || fd.ContainingOneof() != nil { - continue - } - if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) { - v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars - } - } - - if !firstField { - w.writeComma() - } - if err := w.marshalField(fd, v, indent); err != nil { - return err - } - firstField = false - } - - // Handle proto2 extensions. - if md.ExtensionRanges().Len() > 0 { - // Collect a sorted list of all extension descriptor and values. - 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 { - if !firstField { - w.writeComma() - } - if err := w.marshalField(ext.desc, ext.val, indent); err != nil { - return err - } - firstField = false - } - } - - if w.Indent != "" { - w.write("\n") - w.write(indent) - } - w.write("}") - return nil -} - -func (w *jsonWriter) writeComma() { - if w.Indent != "" { - w.write(",\n") - } else { - w.write(",") - } -} - -func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error { - // "If the Any contains a value that has a special JSON mapping, - // it will be converted as follows: {"@type": xxx, "value": yyy}. - // Otherwise, the value will be converted into a JSON object, - // and the "@type" field will be inserted to indicate the actual data type." - md := m.Descriptor() - typeURL := m.Get(md.Fields().ByNumber(1)).String() - rawVal := m.Get(md.Fields().ByNumber(2)).Bytes() - - var m2 protoreflect.Message - if w.AnyResolver != nil { - mi, err := w.AnyResolver.Resolve(typeURL) - if err != nil { - return err - } - m2 = proto.MessageReflect(mi) - } else { - mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL) - if err != nil { - return err - } - m2 = mt.New() - } - - if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil { - return err - } - - if wellKnownType(m2.Descriptor().FullName()) == "" { - return w.marshalMessage(m2, indent, typeURL) - } - - w.write("{") - if w.Indent != "" { - w.write("\n") - } - if err := w.marshalTypeURL(indent, typeURL); err != nil { - return err - } - w.writeComma() - if w.Indent != "" { - w.write(indent) - w.write(w.Indent) - w.write(`"value": `) - } else { - w.write(`"value":`) - } - if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil { - return err - } - if w.Indent != "" { - w.write("\n") - w.write(indent) - } - w.write("}") - return nil -} - -func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error { - if w.Indent != "" { - w.write(indent) - w.write(w.Indent) - } - w.write(`"@type":`) - if w.Indent != "" { - w.write(" ") - } - b, err := json.Marshal(typeURL) - if err != nil { - return err - } - w.write(string(b)) - return nil -} - -// marshalField writes field description and value to the Writer. -func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error { - if w.Indent != "" { - w.write(indent) - w.write(w.Indent) - } - w.write(`"`) - switch { - case fd.IsExtension(): - // For message set, use the fname of the message as the extension name. - name := string(fd.FullName()) - if isMessageSet(fd.ContainingMessage()) { - name = strings.TrimSuffix(name, ".message_set_extension") - } - - w.write("[" + name + "]") - case w.OrigName: - name := string(fd.Name()) - if fd.Kind() == protoreflect.GroupKind { - name = string(fd.Message().Name()) - } - w.write(name) - default: - w.write(string(fd.JSONName())) - } - w.write(`":`) - if w.Indent != "" { - w.write(" ") - } - return w.marshalValue(fd, v, indent) -} - -func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error { - switch { - case fd.IsList(): - w.write("[") - comma := "" - lv := v.List() - for i := 0; i < lv.Len(); i++ { - w.write(comma) - if w.Indent != "" { - w.write("\n") - w.write(indent) - w.write(w.Indent) - w.write(w.Indent) - } - if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil { - return err - } - comma = "," - } - if w.Indent != "" { - w.write("\n") - w.write(indent) - w.write(w.Indent) - } - w.write("]") - return nil - case fd.IsMap(): - kfd := fd.MapKey() - vfd := fd.MapValue() - mv := v.Map() - - // Collect a sorted list of all map keys and values. - 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") - } - }) - - w.write(`{`) - comma := "" - for _, entry := range entries { - w.write(comma) - if w.Indent != "" { - w.write("\n") - w.write(indent) - w.write(w.Indent) - w.write(w.Indent) - } - - s := fmt.Sprint(entry.key.Interface()) - b, err := json.Marshal(s) - if err != nil { - return err - } - w.write(string(b)) - - w.write(`:`) - if w.Indent != "" { - w.write(` `) - } - - if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil { - return err - } - comma = "," - } - if w.Indent != "" { - w.write("\n") - w.write(indent) - w.write(w.Indent) - } - w.write(`}`) - return nil - default: - return w.marshalSingularValue(fd, v, indent) - } -} - -func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error { - switch { - case !v.IsValid(): - w.write("null") - return nil - case fd.Message() != nil: - return w.marshalMessage(v.Message(), indent+w.Indent, "") - case fd.Enum() != nil: - if fd.Enum().FullName() == "google.protobuf.NullValue" { - w.write("null") - return nil - } - - vd := fd.Enum().Values().ByNumber(v.Enum()) - if vd == nil || w.EnumsAsInts { - w.write(strconv.Itoa(int(v.Enum()))) - } else { - w.write(`"` + string(vd.Name()) + `"`) - } - return nil - default: - switch v.Interface().(type) { - case float32, float64: - switch { - case math.IsInf(v.Float(), +1): - w.write(`"Infinity"`) - return nil - case math.IsInf(v.Float(), -1): - w.write(`"-Infinity"`) - return nil - case math.IsNaN(v.Float()): - w.write(`"NaN"`) - return nil - } - case int64, uint64: - w.write(fmt.Sprintf(`"%d"`, v.Interface())) - return nil - } - - b, err := json.Marshal(v.Interface()) - if err != nil { - return err - } - w.write(string(b)) - return nil - } -} diff --git a/vendor/github.com/golang/protobuf/jsonpb/json.go b/vendor/github.com/golang/protobuf/jsonpb/json.go deleted file mode 100644 index 480e2448d..000000000 --- a/vendor/github.com/golang/protobuf/jsonpb/json.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package jsonpb provides functionality to marshal and unmarshal between a -// protocol buffer message and JSON. It follows the specification at -// https://developers.google.com/protocol-buffers/docs/proto3#json. -// -// Do not rely on the default behavior of the standard encoding/json package -// when called on generated message types as it does not operate correctly. -// -// Deprecated: Use the "google.golang.org/protobuf/encoding/protojson" -// package instead. -package jsonpb - -import ( - "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/runtime/protoimpl" -) - -// AnyResolver takes a type URL, present in an Any message, -// and resolves it into an instance of the associated message. -type AnyResolver interface { - Resolve(typeURL string) (proto.Message, error) -} - -type anyResolver struct{ AnyResolver } - -func (r anyResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) { - return r.FindMessageByURL(string(message)) -} - -func (r anyResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) { - m, err := r.Resolve(url) - if err != nil { - return nil, err - } - return protoimpl.X.MessageTypeOf(m), nil -} - -func (r anyResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) { - return protoregistry.GlobalTypes.FindExtensionByName(field) -} - -func (r anyResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { - return protoregistry.GlobalTypes.FindExtensionByNumber(message, field) -} - -func wellKnownType(s protoreflect.FullName) string { - if s.Parent() == "google.protobuf" { - switch s.Name() { - case "Empty", "Any", - "BoolValue", "BytesValue", "StringValue", - "Int32Value", "UInt32Value", "FloatValue", - "Int64Value", "UInt64Value", "DoubleValue", - "Duration", "Timestamp", - "NullValue", "Struct", "Value", "ListValue": - return string(s.Name()) - } - } - return "" -} - -func isMessageSet(md protoreflect.MessageDescriptor) bool { - ms, ok := md.(interface{ IsMessageSet() bool }) - return ok && ms.IsMessageSet() -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go deleted file mode 100644 index 85f9f5736..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ptypes - -import ( - "fmt" - "strings" - - "github.com/golang/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - - anypb "github.com/golang/protobuf/ptypes/any" -) - -const urlPrefix = "type.googleapis.com/" - -// AnyMessageName returns the message name contained in an anypb.Any message. -// Most type assertions should use the Is function instead. -// -// Deprecated: Call the any.MessageName method instead. -func AnyMessageName(any *anypb.Any) (string, error) { - name, err := anyMessageName(any) - return string(name), err -} -func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) { - if any == nil { - return "", fmt.Errorf("message is nil") - } - name := protoreflect.FullName(any.TypeUrl) - if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 { - name = name[i+len("/"):] - } - if !name.IsValid() { - return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl) - } - return name, nil -} - -// MarshalAny marshals the given message m into an anypb.Any message. -// -// Deprecated: Call the anypb.New function instead. -func MarshalAny(m proto.Message) (*anypb.Any, error) { - switch dm := m.(type) { - case DynamicAny: - m = dm.Message - case *DynamicAny: - if dm == nil { - return nil, proto.ErrNil - } - m = dm.Message - } - b, err := proto.Marshal(m) - if err != nil { - return nil, err - } - return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil -} - -// Empty returns a new message of the type specified in an anypb.Any message. -// It returns protoregistry.NotFound if the corresponding message type could not -// be resolved in the global registry. -// -// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead -// to resolve the message name and create a new instance of it. -func Empty(any *anypb.Any) (proto.Message, error) { - name, err := anyMessageName(any) - if err != nil { - return nil, err - } - mt, err := protoregistry.GlobalTypes.FindMessageByName(name) - if err != nil { - return nil, err - } - return proto.MessageV1(mt.New().Interface()), nil -} - -// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message -// into the provided message m. It returns an error if the target message -// does not match the type in the Any message or if an unmarshal error occurs. -// -// The target message m may be a *DynamicAny message. If the underlying message -// type could not be resolved, then this returns protoregistry.NotFound. -// -// Deprecated: Call the any.UnmarshalTo method instead. -func UnmarshalAny(any *anypb.Any, m proto.Message) error { - if dm, ok := m.(*DynamicAny); ok { - if dm.Message == nil { - var err error - dm.Message, err = Empty(any) - if err != nil { - return err - } - } - m = dm.Message - } - - anyName, err := AnyMessageName(any) - if err != nil { - return err - } - msgName := proto.MessageName(m) - if anyName != msgName { - return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName) - } - return proto.Unmarshal(any.Value, m) -} - -// Is reports whether the Any message contains a message of the specified type. -// -// Deprecated: Call the any.MessageIs method instead. -func Is(any *anypb.Any, m proto.Message) bool { - if any == nil || m == nil { - return false - } - name := proto.MessageName(m) - if !strings.HasSuffix(any.TypeUrl, name) { - return false - } - return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/' -} - -// DynamicAny is a value that can be passed to UnmarshalAny to automatically -// allocate a proto.Message for the type specified in an anypb.Any message. -// The allocated message is stored in the embedded proto.Message. -// -// Example: -// var x ptypes.DynamicAny -// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } -// fmt.Printf("unmarshaled message: %v", x.Message) -// -// Deprecated: Use the any.UnmarshalNew method instead to unmarshal -// the any message contents into a new instance of the underlying message. -type DynamicAny struct{ proto.Message } - -func (m DynamicAny) String() string { - if m.Message == nil { - return "" - } - return m.Message.String() -} -func (m DynamicAny) Reset() { - if m.Message == nil { - return - } - m.Message.Reset() -} -func (m DynamicAny) ProtoMessage() { - return -} -func (m DynamicAny) ProtoReflect() protoreflect.Message { - if m.Message == nil { - return nil - } - return dynamicAny{proto.MessageReflect(m.Message)} -} - -type dynamicAny struct{ protoreflect.Message } - -func (m dynamicAny) Type() protoreflect.MessageType { - return dynamicAnyType{m.Message.Type()} -} -func (m dynamicAny) New() protoreflect.Message { - return dynamicAnyType{m.Message.Type()}.New() -} -func (m dynamicAny) Interface() protoreflect.ProtoMessage { - return DynamicAny{proto.MessageV1(m.Message.Interface())} -} - -type dynamicAnyType struct{ protoreflect.MessageType } - -func (t dynamicAnyType) New() protoreflect.Message { - return dynamicAny{t.MessageType.New()} -} -func (t dynamicAnyType) Zero() protoreflect.Message { - return dynamicAny{t.MessageType.Zero()} -} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go b/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go deleted file mode 100644 index 0ef27d33d..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/any/any.pb.go +++ /dev/null @@ -1,62 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/ptypes/any/any.proto - -package any - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - anypb "google.golang.org/protobuf/types/known/anypb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/any.proto. - -type Any = anypb.Any - -var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{ - 0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, - 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, -} - -var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() } -func file_github_com_golang_protobuf_ptypes_any_any_proto_init() { - if File_github_com_golang_protobuf_ptypes_any_any_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_ptypes_any_any_proto = out.File - file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil - file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil - file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go deleted file mode 100644 index d3c33259d..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package ptypes provides functionality for interacting with well-known types. -// -// Deprecated: Well-known types have specialized functionality directly -// injected into the generated packages for each message type. -// See the deprecation notice for each function for the suggested alternative. -package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go deleted file mode 100644 index b2b55dd85..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ptypes - -import ( - "errors" - "fmt" - "time" - - durationpb "github.com/golang/protobuf/ptypes/duration" -) - -// Range of google.protobuf.Duration as specified in duration.proto. -// This is about 10,000 years in seconds. -const ( - maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) - minSeconds = -maxSeconds -) - -// Duration converts a durationpb.Duration to a time.Duration. -// Duration returns an error if dur is invalid or overflows a time.Duration. -// -// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead. -func Duration(dur *durationpb.Duration) (time.Duration, error) { - if err := validateDuration(dur); err != nil { - return 0, err - } - d := time.Duration(dur.Seconds) * time.Second - if int64(d/time.Second) != dur.Seconds { - return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) - } - if dur.Nanos != 0 { - d += time.Duration(dur.Nanos) * time.Nanosecond - if (d < 0) != (dur.Nanos < 0) { - return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) - } - } - return d, nil -} - -// DurationProto converts a time.Duration to a durationpb.Duration. -// -// Deprecated: Call the durationpb.New function instead. -func DurationProto(d time.Duration) *durationpb.Duration { - nanos := d.Nanoseconds() - secs := nanos / 1e9 - nanos -= secs * 1e9 - return &durationpb.Duration{ - Seconds: int64(secs), - Nanos: int32(nanos), - } -} - -// validateDuration determines whether the durationpb.Duration is valid -// according to the definition in google/protobuf/duration.proto. -// A valid durpb.Duration may still be too large to fit into a time.Duration -// Note that the range of durationpb.Duration is about 10,000 years, -// while the range of time.Duration is about 290 years. -func validateDuration(dur *durationpb.Duration) error { - if dur == nil { - return errors.New("duration: nil Duration") - } - if dur.Seconds < minSeconds || dur.Seconds > maxSeconds { - return fmt.Errorf("duration: %v: seconds out of range", dur) - } - if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 { - return fmt.Errorf("duration: %v: nanos out of range", dur) - } - // Seconds and Nanos must have the same sign, unless d.Nanos is zero. - if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) { - return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur) - } - return nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go b/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go deleted file mode 100644 index d0079ee3e..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/ptypes/duration/duration.proto - -package duration - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - durationpb "google.golang.org/protobuf/types/known/durationpb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/duration.proto. - -type Duration = durationpb.Duration - -var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{ - 0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() } -func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() { - if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File - file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil - file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil - file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go deleted file mode 100644 index 8368a3f70..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ptypes - -import ( - "errors" - "fmt" - "time" - - timestamppb "github.com/golang/protobuf/ptypes/timestamp" -) - -// Range of google.protobuf.Duration as specified in timestamp.proto. -const ( - // Seconds field of the earliest valid Timestamp. - // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - minValidSeconds = -62135596800 - // Seconds field just after the latest valid Timestamp. - // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). - maxValidSeconds = 253402300800 -) - -// Timestamp converts a timestamppb.Timestamp to a time.Time. -// It returns an error if the argument is invalid. -// -// Unlike most Go functions, if Timestamp returns an error, the first return -// value is not the zero time.Time. Instead, it is the value obtained from the -// time.Unix function when passed the contents of the Timestamp, in the UTC -// locale. This may or may not be a meaningful time; many invalid Timestamps -// do map to valid time.Times. -// -// A nil Timestamp returns an error. The first return value in that case is -// undefined. -// -// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead. -func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) { - // Don't return the zero value on error, because corresponds to a valid - // timestamp. Instead return whatever time.Unix gives us. - var t time.Time - if ts == nil { - t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp - } else { - t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() - } - return t, validateTimestamp(ts) -} - -// TimestampNow returns a google.protobuf.Timestamp for the current time. -// -// Deprecated: Call the timestamppb.Now function instead. -func TimestampNow() *timestamppb.Timestamp { - ts, err := TimestampProto(time.Now()) - if err != nil { - panic("ptypes: time.Now() out of Timestamp range") - } - return ts -} - -// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. -// It returns an error if the resulting Timestamp is invalid. -// -// Deprecated: Call the timestamppb.New function instead. -func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) { - ts := ×tamppb.Timestamp{ - Seconds: t.Unix(), - Nanos: int32(t.Nanosecond()), - } - if err := validateTimestamp(ts); err != nil { - return nil, err - } - return ts, nil -} - -// TimestampString returns the RFC 3339 string for valid Timestamps. -// For invalid Timestamps, it returns an error message in parentheses. -// -// Deprecated: Call the ts.AsTime method instead, -// followed by a call to the Format method on the time.Time value. -func TimestampString(ts *timestamppb.Timestamp) string { - t, err := Timestamp(ts) - if err != nil { - return fmt.Sprintf("(%v)", err) - } - return t.Format(time.RFC3339Nano) -} - -// validateTimestamp determines whether a Timestamp is valid. -// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01) -// and has a Nanos field in the range [0, 1e9). -// -// If the Timestamp is valid, validateTimestamp returns nil. -// Otherwise, it returns an error that describes the problem. -// -// Every valid Timestamp can be represented by a time.Time, -// but the converse is not true. -func validateTimestamp(ts *timestamppb.Timestamp) error { - if ts == nil { - return errors.New("timestamp: nil Timestamp") - } - if ts.Seconds < minValidSeconds { - return fmt.Errorf("timestamp: %v before 0001-01-01", ts) - } - if ts.Seconds >= maxValidSeconds { - return fmt.Errorf("timestamp: %v after 10000-01-01", ts) - } - if ts.Nanos < 0 || ts.Nanos >= 1e9 { - return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts) - } - return nil -} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go deleted file mode 100644 index a76f80760..000000000 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go +++ /dev/null @@ -1,64 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/ptypes/timestamp/timestamp.proto - -package timestamp - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/timestamp.proto. - -type Timestamp = timestamppb.Timestamp - -var File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = []byte{ - 0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37, - 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() } -func file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() { - if File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto = out.File - file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = nil - file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = nil - file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = nil -} diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go index 595480112..856c75dd4 100644 --- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -18,8 +18,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.22.0 +// protoc-gen-go v1.32.0 +// protoc v4.25.2 // source: grpc/binlog/v1/binarylog.proto package grpc_binarylog_v1 @@ -430,7 +430,7 @@ type ClientHeader struct { MethodName string `protobuf:"bytes,2,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty"` // A single process may be used to run multiple virtual // servers with different identities. - // The authority is the name of such a server identitiy. + // The authority is the name of such a server identity. // It is typically a portion of the URI in the form of // or : . Authority string `protobuf:"bytes,3,opt,name=authority,proto3" json:"authority,omitempty"` diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index e6f2625b6..f0b7f3200 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -1772,6 +1772,8 @@ func parseTarget(target string) (resolver.Target, error) { return resolver.Target{URL: *u}, nil } +// encodeAuthority escapes the authority string based on valid chars defined in +// https://datatracker.ietf.org/doc/html/rfc3986#section-3.2. func encodeAuthority(authority string) string { const upperhex = "0123456789ABCDEF" @@ -1860,27 +1862,15 @@ func (cc *ClientConn) determineAuthority() error { } endpoint := cc.parsedTarget.Endpoint() - target := cc.target - switch { - case authorityFromDialOption != "": + if authorityFromDialOption != "" { cc.authority = authorityFromDialOption - case authorityFromCreds != "": + } else if authorityFromCreds != "" { cc.authority = authorityFromCreds - case strings.HasPrefix(target, "unix:") || strings.HasPrefix(target, "unix-abstract:"): - // TODO: remove when the unix resolver implements optional interface to - // return channel authority. - cc.authority = "localhost" - case strings.HasPrefix(endpoint, ":"): + } else if auth, ok := cc.resolverBuilder.(resolver.AuthorityOverrider); ok { + cc.authority = auth.OverrideAuthority(cc.parsedTarget) + } else if strings.HasPrefix(endpoint, ":") { cc.authority = "localhost" + endpoint - default: - // TODO: Define an optional interface on the resolver builder to return - // the channel authority given the user's dial target. For resolvers - // which don't implement this interface, we will use the endpoint from - // "scheme://authority/endpoint" as the default authority. - // Escape the endpoint to handle use cases where the endpoint - // might not be a valid authority by default. - // For example an endpoint which has multiple paths like - // 'a/b/c', which is not a valid authority by default. + } else { cc.authority = encodeAuthority(endpoint) } channelz.Infof(logger, cc.channelzID, "Channel authority set to %q", cc.authority) diff --git a/vendor/google.golang.org/grpc/encoding/proto/proto.go b/vendor/google.golang.org/grpc/encoding/proto/proto.go index 0ee3d3bae..66d5cdf03 100644 --- a/vendor/google.golang.org/grpc/encoding/proto/proto.go +++ b/vendor/google.golang.org/grpc/encoding/proto/proto.go @@ -23,8 +23,9 @@ package proto import ( "fmt" - "github.com/golang/protobuf/proto" "google.golang.org/grpc/encoding" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/protoadapt" ) // Name is the name registered for the proto compressor. @@ -38,21 +39,34 @@ func init() { type codec struct{} func (codec) Marshal(v any) ([]byte, error) { - vv, ok := v.(proto.Message) - if !ok { + vv := messageV2Of(v) + if vv == nil { return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v) } + return proto.Marshal(vv) } func (codec) Unmarshal(data []byte, v any) error { - vv, ok := v.(proto.Message) - if !ok { + vv := messageV2Of(v) + if vv == nil { return fmt.Errorf("failed to unmarshal, message is %T, want proto.Message", v) } + return proto.Unmarshal(data, vv) } +func messageV2Of(v any) proto.Message { + switch v := v.(type) { + case protoadapt.MessageV1: + return protoadapt.MessageV2Of(v) + case protoadapt.MessageV2: + return v + } + + return nil +} + func (codec) Name() string { return Name } diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go index 0f31274a3..e8456a77c 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go @@ -25,11 +25,12 @@ import ( "sync/atomic" "time" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" binlogpb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" ) type callIDGenerator struct { @@ -88,7 +89,7 @@ func NewTruncatingMethodLogger(h, m uint64) *TruncatingMethodLogger { // in TruncatingMethodLogger as possible. func (ml *TruncatingMethodLogger) Build(c LogEntryConfig) *binlogpb.GrpcLogEntry { m := c.toProto() - timestamp, _ := ptypes.TimestampProto(time.Now()) + timestamp := timestamppb.Now() m.Timestamp = timestamp m.CallId = ml.callID m.SequenceIdWithinCall = ml.idWithinCallGen.next() @@ -178,7 +179,7 @@ func (c *ClientHeader) toProto() *binlogpb.GrpcLogEntry { Authority: c.Authority, } if c.Timeout > 0 { - clientHeader.Timeout = ptypes.DurationProto(c.Timeout) + clientHeader.Timeout = durationpb.New(c.Timeout) } ret := &binlogpb.GrpcLogEntry{ Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, diff --git a/vendor/google.golang.org/grpc/internal/binarylog/sink.go b/vendor/google.golang.org/grpc/internal/binarylog/sink.go index 264de387c..9ea598b14 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/sink.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/sink.go @@ -25,8 +25,8 @@ import ( "sync" "time" - "github.com/golang/protobuf/proto" binlogpb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + "google.golang.org/protobuf/proto" ) var ( diff --git a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go index aa97273e7..0126d6b51 100644 --- a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go +++ b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go @@ -1,3 +1,8 @@ +//go:build !go1.21 + +// TODO: when this file is deleted (after Go 1.20 support is dropped), delete +// all of grpcrand and call the rand package directly. + /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand_go1.21.go b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand_go1.21.go new file mode 100644 index 000000000..c37299af1 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand_go1.21.go @@ -0,0 +1,73 @@ +//go:build go1.21 + +/* + * + * Copyright 2024 gRPC 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 grpcrand implements math/rand functions in a concurrent-safe way +// with a global random source, independent of math/rand's global source. +package grpcrand + +import "math/rand" + +// This implementation will be used for Go version 1.21 or newer. +// For older versions, the original implementation with mutex will be used. + +// Int implements rand.Int on the grpcrand global source. +func Int() int { + return rand.Int() +} + +// Int63n implements rand.Int63n on the grpcrand global source. +func Int63n(n int64) int64 { + return rand.Int63n(n) +} + +// Intn implements rand.Intn on the grpcrand global source. +func Intn(n int) int { + return rand.Intn(n) +} + +// Int31n implements rand.Int31n on the grpcrand global source. +func Int31n(n int32) int32 { + return rand.Int31n(n) +} + +// Float64 implements rand.Float64 on the grpcrand global source. +func Float64() float64 { + return rand.Float64() +} + +// Uint64 implements rand.Uint64 on the grpcrand global source. +func Uint64() uint64 { + return rand.Uint64() +} + +// Uint32 implements rand.Uint32 on the grpcrand global source. +func Uint32() uint32 { + return rand.Uint32() +} + +// ExpFloat64 implements rand.ExpFloat64 on the grpcrand global source. +func ExpFloat64() float64 { + return rand.ExpFloat64() +} + +// Shuffle implements rand.Shuffle on the grpcrand global source. +var Shuffle = func(n int, f func(int, int)) { + rand.Shuffle(n, f) +} diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go index 2549fe8e3..6c7ea6a53 100644 --- a/vendor/google.golang.org/grpc/internal/internal.go +++ b/vendor/google.golang.org/grpc/internal/internal.go @@ -57,7 +57,7 @@ var ( // GetXDSHandshakeInfoForTesting returns a pointer to the xds.HandshakeInfo // stored in the passed in attributes. This is set by // credentials/xds/xds.go. - GetXDSHandshakeInfoForTesting any // func (*attributes.Attributes) *xds.HandshakeInfo + GetXDSHandshakeInfoForTesting any // func (*attributes.Attributes) *unsafe.Pointer // GetServerCredentials returns the transport credentials configured on a // gRPC server. An xDS-enabled server needs to know what type of credentials // is configured on the underlying gRPC server. This is set by server.go. @@ -68,11 +68,6 @@ var ( // This is used in the 1.0 release of gcp/observability, and thus must not be // deleted or changed. CanonicalString any // func (codes.Code) string - // DrainServerTransports initiates a graceful close of existing connections - // on a gRPC server accepted on the provided listener address. An - // xDS-enabled server invokes this method on a grpc.Server when a particular - // listener moves to "not-serving" mode. - DrainServerTransports any // func(*grpc.Server, string) // IsRegisteredMethod returns whether the passed in method is registered as // a method on the server. IsRegisteredMethod any // func(*grpc.Server, string) bool @@ -188,6 +183,19 @@ var ( ExitIdleModeForTesting any // func(*grpc.ClientConn) error ChannelzTurnOffForTesting func() + + // TriggerXDSResourceNameNotFoundForTesting triggers the resource-not-found + // error for a given resource type and name. This is usually triggered when + // the associated watch timer fires. For testing purposes, having this + // function makes events more predictable than relying on timer events. + TriggerXDSResourceNameNotFoundForTesting any // func(func(xdsresource.Type, string), string, string) error + + // TriggerXDSResourceNotFoundClient invokes the testing xDS Client singleton + // to invoke resource not found for a resource type name and resource name. + TriggerXDSResourceNameNotFoundClient any // func(string, string) error + + // FromOutgoingContextRaw returns the un-merged, intermediary contents of metadata.rawMD. + FromOutgoingContextRaw any // func(context.Context) (metadata.MD, [][]string, bool) ) // HealthChecker defines the signature of the client-side LB channel health checking function. diff --git a/vendor/google.golang.org/grpc/internal/pretty/pretty.go b/vendor/google.golang.org/grpc/internal/pretty/pretty.go index 703319137..52cfab1b9 100644 --- a/vendor/google.golang.org/grpc/internal/pretty/pretty.go +++ b/vendor/google.golang.org/grpc/internal/pretty/pretty.go @@ -24,7 +24,6 @@ import ( "encoding/json" "fmt" - "github.com/golang/protobuf/jsonpb" protov1 "github.com/golang/protobuf/proto" "google.golang.org/protobuf/encoding/protojson" protov2 "google.golang.org/protobuf/proto" @@ -38,15 +37,15 @@ const jsonIndent = " " func ToJSON(e any) string { switch ee := e.(type) { case protov1.Message: - mm := jsonpb.Marshaler{Indent: jsonIndent} - ret, err := mm.MarshalToString(ee) + mm := protojson.MarshalOptions{Indent: jsonIndent} + ret, err := mm.Marshal(protov1.MessageV2(ee)) if err != nil { // This may fail for proto.Anys, e.g. for xDS v2, LDS, the v2 // messages are not imported, and this will fail because the message // is not found. return fmt.Sprintf("%+v", ee) } - return ret + return string(ret) case protov2.Message: mm := protojson.MarshalOptions{ Multiline: true, diff --git a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go index 160911687..27cd81af9 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go +++ b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go @@ -61,6 +61,10 @@ func (b *builder) Scheme() string { return b.scheme } +func (b *builder) OverrideAuthority(resolver.Target) string { + return "localhost" +} + type nopResolver struct { } diff --git a/vendor/google.golang.org/grpc/internal/status/status.go b/vendor/google.golang.org/grpc/internal/status/status.go index 03ef2fedd..c7dbc8205 100644 --- a/vendor/google.golang.org/grpc/internal/status/status.go +++ b/vendor/google.golang.org/grpc/internal/status/status.go @@ -31,10 +31,11 @@ import ( "errors" "fmt" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" spb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/protoadapt" + "google.golang.org/protobuf/types/known/anypb" ) // Status represents an RPC status code, message, and details. It is immutable @@ -130,14 +131,14 @@ func (s *Status) Err() error { // WithDetails returns a new status with the provided details messages appended to the status. // If any errors are encountered, it returns nil and the first error encountered. -func (s *Status) WithDetails(details ...proto.Message) (*Status, error) { +func (s *Status) WithDetails(details ...protoadapt.MessageV1) (*Status, error) { if s.Code() == codes.OK { return nil, errors.New("no error details for status with code OK") } // s.Code() != OK implies that s.Proto() != nil. p := s.Proto() for _, detail := range details { - any, err := ptypes.MarshalAny(detail) + any, err := anypb.New(protoadapt.MessageV2Of(detail)) if err != nil { return nil, err } @@ -154,12 +155,12 @@ func (s *Status) Details() []any { } details := make([]any, 0, len(s.s.Details)) for _, any := range s.s.Details { - detail := &ptypes.DynamicAny{} - if err := ptypes.UnmarshalAny(any, detail); err != nil { + detail, err := any.UnmarshalNew() + if err != nil { details = append(details, err) continue } - details = append(details, detail.Message) + details = append(details, detail) } return details } diff --git a/vendor/google.golang.org/grpc/internal/tcp_keepalive_nonunix.go b/vendor/google.golang.org/grpc/internal/tcp_keepalive_others.go similarity index 96% rename from vendor/google.golang.org/grpc/internal/tcp_keepalive_nonunix.go rename to vendor/google.golang.org/grpc/internal/tcp_keepalive_others.go index aeffd3e1c..4f347edd4 100644 --- a/vendor/google.golang.org/grpc/internal/tcp_keepalive_nonunix.go +++ b/vendor/google.golang.org/grpc/internal/tcp_keepalive_others.go @@ -1,4 +1,4 @@ -//go:build !unix +//go:build !unix && !windows /* * Copyright 2023 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go b/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go new file mode 100644 index 000000000..fd7d43a89 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go @@ -0,0 +1,54 @@ +//go:build windows + +/* + * Copyright 2023 gRPC 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 internal + +import ( + "net" + "syscall" + "time" + + "golang.org/x/sys/windows" +) + +// NetDialerWithTCPKeepalive returns a net.Dialer that enables TCP keepalives on +// the underlying connection with OS default values for keepalive parameters. +// +// TODO: Once https://github.com/golang/go/issues/62254 lands, and the +// appropriate Go version becomes less than our least supported Go version, we +// should look into using the new API to make things more straightforward. +func NetDialerWithTCPKeepalive() *net.Dialer { + return &net.Dialer{ + // Setting a negative value here prevents the Go stdlib from overriding + // the values of TCP keepalive time and interval. It also prevents the + // Go stdlib from enabling TCP keepalives by default. + KeepAlive: time.Duration(-1), + // This method is called after the underlying network socket is created, + // but before dialing the socket (or calling its connect() method). The + // combination of unconditionally enabling TCP keepalives here, and + // disabling the overriding of TCP keepalive parameters by setting the + // KeepAlive field to a negative value above, results in OS defaults for + // the TCP keealive interval and time parameters. + Control: func(_, _ string, c syscall.RawConn) error { + return c.Control(func(fd uintptr) { + windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_KEEPALIVE, 1) + }) + }, + } +} diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go index b330ccedc..83c382982 100644 --- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go @@ -535,8 +535,8 @@ const minBatchSize = 1000 // size is too low to give stream goroutines a chance to fill it up. // // Upon exiting, if the error causing the exit is not an I/O error, run() -// flushes and closes the underlying connection. Otherwise, the connection is -// left open to allow the I/O error to be encountered by the reader instead. +// flushes the underlying connection. The connection is always left open to +// allow different closing behavior on the client and server. func (l *loopyWriter) run() (err error) { defer func() { if l.logger.V(logLevel) { @@ -544,7 +544,6 @@ func (l *loopyWriter) run() (err error) { } if !isIOError(err) { l.framer.writer.Flush() - l.conn.Close() } l.cbuf.finish() }() diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go index a9d70e2a1..bd39ff9a2 100644 --- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -35,7 +35,6 @@ import ( "sync" "time" - "github.com/golang/protobuf/proto" "golang.org/x/net/http2" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -45,6 +44,7 @@ import ( "google.golang.org/grpc/peer" "google.golang.org/grpc/stats" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" ) // NewServerHandlerTransport returns a ServerTransport handling gRPC from diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 59f67655a..eff879964 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -59,6 +59,8 @@ import ( // atomically. var clientConnectionCounter uint64 +var metadataFromOutgoingContextRaw = internal.FromOutgoingContextRaw.(func(context.Context) (metadata.MD, [][]string, bool)) + // http2Client implements the ClientTransport interface with HTTP2. type http2Client struct { lastRead int64 // Keep this field 64-bit aligned. Accessed atomically. @@ -449,7 +451,13 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } go func() { t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst, t.conn, t.logger) - t.loopy.run() + if err := t.loopy.run(); !isIOError(err) { + // Immediately close the connection, as the loopy writer returns + // when there are no more active streams and we were draining (the + // server sent a GOAWAY). For I/O errors, the reader will hit it + // after draining any remaining incoming data. + t.conn.Close() + } close(t.writerDone) }() return t, nil @@ -568,7 +576,7 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-trace-bin", Value: encodeBinHeader(b)}) } - if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok { + if md, added, ok := metadataFromOutgoingContextRaw(ctx); ok { var k string for k, vv := range md { // HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set. @@ -1323,10 +1331,8 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { for streamID, stream := range t.activeStreams { if streamID > id && streamID <= upperLimit { // The stream was unprocessed by the server. - if streamID > id && streamID <= upperLimit { - atomic.StoreUint32(&stream.unprocessed, 1) - streamsToClose = append(streamsToClose, stream) - } + atomic.StoreUint32(&stream.unprocessed, 1) + streamsToClose = append(streamsToClose, stream) } } t.mu.Unlock() diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index 680c9eba0..3839c1ade 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -32,13 +32,13 @@ import ( "sync/atomic" "time" - "github.com/golang/protobuf/proto" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcutil" "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/internal/syscall" + "google.golang.org/protobuf/proto" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -322,8 +322,24 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, go func() { t.loopy = newLoopyWriter(serverSide, t.framer, t.controlBuf, t.bdpEst, t.conn, t.logger) t.loopy.ssGoAwayHandler = t.outgoingGoAwayHandler - t.loopy.run() + err := t.loopy.run() close(t.loopyWriterDone) + if !isIOError(err) { + // Close the connection if a non-I/O error occurs (for I/O errors + // the reader will also encounter the error and close). Wait 1 + // second before closing the connection, or when the reader is done + // (i.e. the client already closed the connection or a connection + // error occurred). This avoids the potential problem where there + // is unread data on the receive side of the connection, which, if + // closed, would lead to a TCP RST instead of FIN, and the client + // encountering errors. For more info: + // https://github.com/grpc/grpc-go/issues/5358 + select { + case <-t.readerDone: + case <-time.After(time.Second): + } + t.conn.Close() + } }() go t.keepalive() return t, nil @@ -609,8 +625,8 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade // traceCtx attaches trace to ctx and returns the new context. func (t *http2Server) HandleStreams(ctx context.Context, handle func(*Stream)) { defer func() { - <-t.loopyWriterDone close(t.readerDone) + <-t.loopyWriterDone }() for { t.controlBuf.throttle() @@ -636,10 +652,6 @@ func (t *http2Server) HandleStreams(ctx context.Context, handle func(*Stream)) { } continue } - if err == io.EOF || err == io.ErrUnexpectedEOF { - t.Close(err) - return - } t.Close(err) return } @@ -960,7 +972,12 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { } } if err := t.writeHeaderLocked(s); err != nil { - return status.Convert(err).Err() + switch e := err.(type) { + case ConnectionError: + return status.Error(codes.Unavailable, e.Desc) + default: + return status.Convert(err).Err() + } } return nil } @@ -1324,6 +1341,7 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) { if err := t.framer.fr.WriteGoAway(sid, g.code, g.debugData); err != nil { return false, err } + t.framer.writer.Flush() if retErr != nil { return false, retErr } @@ -1344,7 +1362,7 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) { return false, err } go func() { - timer := time.NewTimer(time.Minute) + timer := time.NewTimer(5 * time.Second) defer timer.Stop() select { case <-t.drainEvent.Done(): diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index b7b8fec18..d3796c256 100644 --- a/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -28,6 +28,7 @@ import ( "fmt" "io" "net" + "strings" "sync" "sync/atomic" "time" @@ -362,8 +363,12 @@ func (s *Stream) SendCompress() string { // ClientAdvertisedCompressors returns the compressor names advertised by the // client via grpc-accept-encoding header. -func (s *Stream) ClientAdvertisedCompressors() string { - return s.clientAdvertisedCompressors +func (s *Stream) ClientAdvertisedCompressors() []string { + values := strings.Split(s.clientAdvertisedCompressors, ",") + for i, v := range values { + values[i] = strings.TrimSpace(v) + } + return values } // Done returns a channel which is closed when it receives the final status diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go index 494468257..1e9485fd6 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/metadata/metadata.go @@ -25,8 +25,14 @@ import ( "context" "fmt" "strings" + + "google.golang.org/grpc/internal" ) +func init() { + internal.FromOutgoingContextRaw = fromOutgoingContextRaw +} + // DecodeKeyValue returns k, v, nil. // // Deprecated: use k and v directly instead. @@ -238,16 +244,13 @@ func copyOf(v []string) []string { return vals } -// FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD. +// fromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD. // // Remember to perform strings.ToLower on the keys, for both the returned MD (MD // is a map, there's no guarantee it's created using our helper functions) and // the extra kv pairs (AppendToOutgoingContext doesn't turn them into // lowercase). -// -// This is intended for gRPC-internal use ONLY. Users should use -// FromOutgoingContext instead. -func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { +func fromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) if !ok { return nil, nil, false diff --git a/vendor/google.golang.org/grpc/resolver/resolver.go b/vendor/google.golang.org/grpc/resolver/resolver.go index bd1c7d01b..d72f21c1b 100644 --- a/vendor/google.golang.org/grpc/resolver/resolver.go +++ b/vendor/google.golang.org/grpc/resolver/resolver.go @@ -168,6 +168,9 @@ type BuildOptions struct { // field. In most cases though, it is not appropriate, and this field may // be ignored. Dialer func(context.Context, string) (net.Conn, error) + // Authority is the effective authority of the clientconn for which the + // resolver is built. + Authority string } // An Endpoint is one network endpoint, or server, which may have multiple @@ -314,3 +317,13 @@ type Resolver interface { // Close closes the resolver. Close() } + +// AuthorityOverrider is implemented by Builders that wish to override the +// default authority for the ClientConn. +// By default, the authority used is target.Endpoint(). +type AuthorityOverrider interface { + // OverrideAuthority returns the authority to use for a ClientConn with the + // given target. The implementation must generate it without blocking, + // typically in line, and must keep it unchanged. + OverrideAuthority(Target) string +} diff --git a/vendor/google.golang.org/grpc/resolver_wrapper.go b/vendor/google.golang.org/grpc/resolver_wrapper.go index c79bab121..f845ac958 100644 --- a/vendor/google.golang.org/grpc/resolver_wrapper.go +++ b/vendor/google.golang.org/grpc/resolver_wrapper.go @@ -75,6 +75,7 @@ func (ccr *ccResolverWrapper) start() error { DialCreds: ccr.cc.dopts.copts.TransportCredentials, CredsBundle: ccr.cc.dopts.copts.CredsBundle, Dialer: ccr.cc.dopts.copts.Dialer, + Authority: ccr.cc.authority, } var err error ccr.resolver, err = ccr.cc.resolverBuilder.Build(ccr.cc.parsedTarget, ccr, opts) diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index b7723aa09..82493d237 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -189,6 +189,20 @@ type EmptyCallOption struct{} func (EmptyCallOption) before(*callInfo) error { return nil } func (EmptyCallOption) after(*callInfo, *csAttempt) {} +// StaticMethod returns a CallOption which specifies that a call is being made +// to a method that is static, which means the method is known at compile time +// and doesn't change at runtime. This can be used as a signal to stats plugins +// that this method is safe to include as a key to a measurement. +func StaticMethod() CallOption { + return StaticMethodCallOption{} +} + +// StaticMethodCallOption is a CallOption that specifies that a call comes +// from a static method. +type StaticMethodCallOption struct { + EmptyCallOption +} + // Header returns a CallOptions that retrieves the header metadata // for a unary RPC. func Header(md *metadata.MD) CallOption { @@ -640,14 +654,18 @@ func encode(c baseCodec, msg any) ([]byte, error) { return b, nil } -// compress returns the input bytes compressed by compressor or cp. If both -// compressors are nil, returns nil. +// compress returns the input bytes compressed by compressor or cp. +// If both compressors are nil, or if the message has zero length, returns nil, +// indicating no compression was done. // // TODO(dfawley): eliminate cp parameter by wrapping Compressor in an encoding.Compressor. func compress(in []byte, cp Compressor, compressor encoding.Compressor) ([]byte, error) { if compressor == nil && cp == nil { return nil, nil } + if len(in) == 0 { + return nil, nil + } wrapErr := func(err error) error { return status.Errorf(codes.Internal, "grpc: error while compressing: %v", err.Error()) } @@ -726,17 +744,19 @@ type payloadInfo struct { uncompressedBytes []byte } -func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) ([]byte, error) { - pf, buf, err := p.recvMsg(maxReceiveMessageSize) +// recvAndDecompress reads a message from the stream, decompressing it if necessary. +// +// Cancelling the returned cancel function releases the buffer back to the pool. So the caller should cancel as soon as +// the buffer is no longer needed. +func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor, +) (uncompressedBuf []byte, cancel func(), err error) { + pf, compressedBuf, err := p.recvMsg(maxReceiveMessageSize) if err != nil { - return nil, err - } - if payInfo != nil { - payInfo.compressedLength = len(buf) + return nil, nil, err } if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil); st != nil { - return nil, st.Err() + return nil, nil, st.Err() } var size int @@ -744,21 +764,35 @@ func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxRecei // To match legacy behavior, if the decompressor is set by WithDecompressor or RPCDecompressor, // use this decompressor as the default. if dc != nil { - buf, err = dc.Do(bytes.NewReader(buf)) - size = len(buf) + uncompressedBuf, err = dc.Do(bytes.NewReader(compressedBuf)) + size = len(uncompressedBuf) } else { - buf, size, err = decompress(compressor, buf, maxReceiveMessageSize) + uncompressedBuf, size, err = decompress(compressor, compressedBuf, maxReceiveMessageSize) } if err != nil { - return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err) + return nil, nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err) } if size > maxReceiveMessageSize { // TODO: Revisit the error code. Currently keep it consistent with java // implementation. - return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max (%d vs. %d)", size, maxReceiveMessageSize) + return nil, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max (%d vs. %d)", size, maxReceiveMessageSize) } + } else { + uncompressedBuf = compressedBuf } - return buf, nil + + if payInfo != nil { + payInfo.compressedLength = len(compressedBuf) + payInfo.uncompressedBytes = uncompressedBuf + + cancel = func() {} + } else { + cancel = func() { + p.recvBufferPool.Put(&compressedBuf) + } + } + + return uncompressedBuf, cancel, nil } // Using compressor, decompress d, returning data and size. @@ -778,6 +812,9 @@ func decompress(compressor encoding.Compressor, d []byte, maxReceiveMessageSize // size is used as an estimate to size the buffer, but we // will read more data if available. // +MinRead so ReadFrom will not reallocate if size is correct. + // + // TODO: If we ensure that the buffer size is the same as the DecompressedSize, + // we can also utilize the recv buffer pool here. buf := bytes.NewBuffer(make([]byte, 0, size+bytes.MinRead)) bytesRead, err := buf.ReadFrom(io.LimitReader(dcReader, int64(maxReceiveMessageSize)+1)) return buf.Bytes(), int(bytesRead), err @@ -793,18 +830,15 @@ func decompress(compressor encoding.Compressor, d []byte, maxReceiveMessageSize // dc takes precedence over compressor. // TODO(dfawley): wrap the old compressor/decompressor using the new API? func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m any, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) error { - buf, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, payInfo, compressor) + buf, cancel, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, payInfo, compressor) if err != nil { return err } + defer cancel() + if err := c.Unmarshal(buf, m); err != nil { return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message: %v", err) } - if payInfo != nil { - payInfo.uncompressedBytes = buf - } else { - p.recvBufferPool.Put(&buf) - } return nil } @@ -954,6 +988,7 @@ const ( SupportPackageIsVersion5 = true SupportPackageIsVersion6 = true SupportPackageIsVersion7 = true + SupportPackageIsVersion8 = true ) const grpcUA = "grpc-go/" + Version diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 682fa1831..a6a11704b 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -33,8 +33,6 @@ import ( "sync/atomic" "time" - "golang.org/x/net/trace" - "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/encoding" @@ -74,9 +72,6 @@ func init() { return srv.isRegisteredMethod(method) } internal.ServerFromContext = serverFromContext - internal.DrainServerTransports = func(srv *Server, addr string) { - srv.drainServerTransports(addr) - } internal.AddGlobalServerOptions = func(opt ...ServerOption) { globalServerOptions = append(globalServerOptions, opt...) } @@ -134,12 +129,13 @@ type Server struct { drain bool cv *sync.Cond // signaled when connections close for GracefulStop services map[string]*serviceInfo // service name -> service info - events trace.EventLog + events traceEventLog quit *grpcsync.Event done *grpcsync.Event channelzRemoveOnce sync.Once - serveWG sync.WaitGroup // counts active Serve goroutines for GracefulStop + serveWG sync.WaitGroup // counts active Serve goroutines for Stop/GracefulStop + handlersWG sync.WaitGroup // counts active method handler goroutines channelzID *channelz.Identifier czData *channelzData @@ -176,6 +172,7 @@ type serverOptions struct { headerTableSize *uint32 numServerWorkers uint32 recvBufferPool SharedBufferPool + waitForHandlers bool } var defaultServerOptions = serverOptions{ @@ -573,6 +570,21 @@ func NumStreamWorkers(numServerWorkers uint32) ServerOption { }) } +// WaitForHandlers cause Stop to wait until all outstanding method handlers have +// exited before returning. If false, Stop will return as soon as all +// connections have closed, but method handlers may still be running. By +// default, Stop does not wait for method handlers to return. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func WaitForHandlers(w bool) ServerOption { + return newFuncServerOption(func(o *serverOptions) { + o.waitForHandlers = w + }) +} + // RecvBufferPool returns a ServerOption that configures the server // to use the provided shared buffer pool for parsing incoming messages. Depending // on the application's workload, this could result in reduced memory allocation. @@ -656,7 +668,7 @@ func NewServer(opt ...ServerOption) *Server { s.cv = sync.NewCond(&s.mu) if EnableTracing { _, file, line, _ := runtime.Caller(1) - s.events = trace.NewEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line)) + s.events = newTraceEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line)) } if s.opts.numServerWorkers > 0 { @@ -932,6 +944,12 @@ func (s *Server) handleRawConn(lisAddr string, rawConn net.Conn) { return } + if cc, ok := rawConn.(interface { + PassServerTransport(transport.ServerTransport) + }); ok { + cc.PassServerTransport(st) + } + if !s.addConn(lisAddr, st) { return } @@ -941,15 +959,6 @@ func (s *Server) handleRawConn(lisAddr string, rawConn net.Conn) { }() } -func (s *Server) drainServerTransports(addr string) { - s.mu.Lock() - conns := s.conns[addr] - for st := range conns { - st.Drain("") - } - s.mu.Unlock() -} - // newHTTP2Transport sets up a http/2 transport (using the // gRPC http2 server transport in transport/http2_server.go). func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport { @@ -1010,9 +1019,11 @@ func (s *Server) serveStreams(ctx context.Context, st transport.ServerTransport, streamQuota := newHandlerQuota(s.opts.maxConcurrentStreams) st.HandleStreams(ctx, func(stream *transport.Stream) { + s.handlersWG.Add(1) streamQuota.acquire() f := func() { defer streamQuota.release() + defer s.handlersWG.Done() s.handleStream(st, stream) } @@ -1331,7 +1342,8 @@ func (s *Server) processUnaryRPC(ctx context.Context, t transport.ServerTranspor if len(shs) != 0 || len(binlogs) != 0 { payInfo = &payloadInfo{} } - d, err := recvAndDecompress(&parser{r: stream, recvBufferPool: s.opts.recvBufferPool}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp) + + d, cancel, err := recvAndDecompress(&parser{r: stream, recvBufferPool: s.opts.recvBufferPool}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp) if err != nil { if e := t.WriteStatus(stream, status.Convert(err)); e != nil { channelz.Warningf(logger, s.channelzID, "grpc: Server.processUnaryRPC failed to write status: %v", e) @@ -1342,6 +1354,8 @@ func (s *Server) processUnaryRPC(ctx context.Context, t transport.ServerTranspor t.IncrMsgRecv() } df := func(v any) error { + defer cancel() + if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil { return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err) } @@ -1721,8 +1735,8 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str ctx = contextWithServer(ctx, s) var ti *traceInfo if EnableTracing { - tr := trace.New("grpc.Recv."+methodFamily(stream.Method()), stream.Method()) - ctx = trace.NewContext(ctx, tr) + tr := newTrace("grpc.Recv."+methodFamily(stream.Method()), stream.Method()) + ctx = newTraceContext(ctx, tr) ti = &traceInfo{ tr: tr, firstLine: firstLine{ @@ -1911,6 +1925,10 @@ func (s *Server) stop(graceful bool) { s.serverWorkerChannelClose() } + if graceful || s.opts.waitForHandlers { + s.handlersWG.Wait() + } + if s.events != nil { s.events.Finish() s.events = nil @@ -2102,7 +2120,7 @@ func ClientSupportedCompressors(ctx context.Context) ([]string, error) { return nil, fmt.Errorf("failed to fetch the stream from the given context %v", ctx) } - return strings.Split(stream.ClientAdvertisedCompressors(), ","), nil + return stream.ClientAdvertisedCompressors(), nil } // SetTrailer sets the trailer metadata that will be sent when an RPC returns. @@ -2142,7 +2160,7 @@ func (c *channelzServer) ChannelzMetric() *channelz.ServerInternalMetric { // validateSendCompressor returns an error when given compressor name cannot be // handled by the server or the client based on the advertised compressors. -func validateSendCompressor(name, clientCompressors string) error { +func validateSendCompressor(name string, clientCompressors []string) error { if name == encoding.Identity { return nil } @@ -2151,7 +2169,7 @@ func validateSendCompressor(name, clientCompressors string) error { return fmt.Errorf("compressor not registered %q", name) } - for _, c := range strings.Split(clientCompressors, ",") { + for _, c := range clientCompressors { if c == name { return nil // found match } diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index b14b2fbea..814e99835 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -27,7 +27,6 @@ import ( "sync" "time" - "golang.org/x/net/trace" "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" "google.golang.org/grpc/encoding" @@ -48,6 +47,8 @@ import ( "google.golang.org/grpc/status" ) +var metadataFromOutgoingContextRaw = internal.FromOutgoingContextRaw.(func(context.Context) (metadata.MD, [][]string, bool)) + // StreamHandler defines the handler called by gRPC server to complete the // execution of a streaming RPC. // @@ -184,7 +185,7 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth // when the RPC completes. opts = append([]CallOption{OnFinish(func(error) { cc.idlenessMgr.OnCallEnd() })}, opts...) - if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok { + if md, added, ok := metadataFromOutgoingContextRaw(ctx); ok { // validate md if err := imetadata.Validate(md); err != nil { return nil, status.Error(codes.Internal, err.Error()) @@ -429,7 +430,7 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error) var trInfo *traceInfo if EnableTracing { trInfo = &traceInfo{ - tr: trace.New("grpc.Sent."+methodFamily(method), method), + tr: newTrace("grpc.Sent."+methodFamily(method), method), firstLine: firstLine{ client: true, }, @@ -438,7 +439,7 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error) trInfo.firstLine.deadline = time.Until(deadline) } trInfo.tr.LazyLog(&trInfo.firstLine, false) - ctx = trace.NewContext(ctx, trInfo.tr) + ctx = newTraceContext(ctx, trInfo.tr) } if cs.cc.parsedTarget.URL.Scheme == internal.GRPCResolverSchemeExtraMetadata { diff --git a/vendor/google.golang.org/grpc/trace.go b/vendor/google.golang.org/grpc/trace.go index 9ded79321..10f4f798f 100644 --- a/vendor/google.golang.org/grpc/trace.go +++ b/vendor/google.golang.org/grpc/trace.go @@ -26,8 +26,6 @@ import ( "strings" "sync" "time" - - "golang.org/x/net/trace" ) // EnableTracing controls whether to trace RPCs using the golang.org/x/net/trace package. @@ -44,9 +42,31 @@ func methodFamily(m string) string { return m } +// traceEventLog mirrors golang.org/x/net/trace.EventLog. +// +// It exists in order to avoid importing x/net/trace on grpcnotrace builds. +type traceEventLog interface { + Printf(format string, a ...any) + Errorf(format string, a ...any) + Finish() +} + +// traceLog mirrors golang.org/x/net/trace.Trace. +// +// It exists in order to avoid importing x/net/trace on grpcnotrace builds. +type traceLog interface { + LazyLog(x fmt.Stringer, sensitive bool) + LazyPrintf(format string, a ...any) + SetError() + SetRecycler(f func(any)) + SetTraceInfo(traceID, spanID uint64) + SetMaxEvents(m int) + Finish() +} + // traceInfo contains tracing information for an RPC. type traceInfo struct { - tr trace.Trace + tr traceLog firstLine firstLine } diff --git a/vendor/google.golang.org/grpc/trace_notrace.go b/vendor/google.golang.org/grpc/trace_notrace.go new file mode 100644 index 000000000..1da3a2308 --- /dev/null +++ b/vendor/google.golang.org/grpc/trace_notrace.go @@ -0,0 +1,52 @@ +//go:build grpcnotrace + +/* + * + * Copyright 2024 gRPC 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 grpc + +// grpcnotrace can be used to avoid importing golang.org/x/net/trace, which in +// turn enables binaries using gRPC-Go for dead code elimination, which can +// yield 10-15% improvements in binary size when tracing is not needed. + +import ( + "context" + "fmt" +) + +type notrace struct{} + +func (notrace) LazyLog(x fmt.Stringer, sensitive bool) {} +func (notrace) LazyPrintf(format string, a ...any) {} +func (notrace) SetError() {} +func (notrace) SetRecycler(f func(any)) {} +func (notrace) SetTraceInfo(traceID, spanID uint64) {} +func (notrace) SetMaxEvents(m int) {} +func (notrace) Finish() {} + +func newTrace(family, title string) traceLog { + return notrace{} +} + +func newTraceContext(ctx context.Context, tr traceLog) context.Context { + return ctx +} + +func newTraceEventLog(family, title string) traceEventLog { + return nil +} diff --git a/vendor/google.golang.org/grpc/trace_withtrace.go b/vendor/google.golang.org/grpc/trace_withtrace.go new file mode 100644 index 000000000..88d6e8571 --- /dev/null +++ b/vendor/google.golang.org/grpc/trace_withtrace.go @@ -0,0 +1,39 @@ +//go:build !grpcnotrace + +/* + * + * Copyright 2024 gRPC 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 grpc + +import ( + "context" + + t "golang.org/x/net/trace" +) + +func newTrace(family, title string) traceLog { + return t.New(family, title) +} + +func newTraceContext(ctx context.Context, tr traceLog) context.Context { + return t.NewContext(ctx, tr) +} + +func newTraceEventLog(family, title string) traceEventLog { + return t.NewEventLog(family, title) +} diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index dc2cea59c..46ad8113f 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.60.1" +const Version = "1.62.1" diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh index 896dc38f5..7a33c215b 100644 --- a/vendor/google.golang.org/grpc/vet.sh +++ b/vendor/google.golang.org/grpc/vet.sh @@ -41,7 +41,7 @@ if [[ "$1" = "-install" ]]; then popd if [[ -z "${VET_SKIP_PROTO}" ]]; then if [[ "${GITHUB_ACTIONS}" = "true" ]]; then - PROTOBUF_VERSION=22.0 # a.k.a v4.22.0 in pb.go files. + PROTOBUF_VERSION=25.2 # a.k.a. v4.22.0 in pb.go files. PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip pushd /home/runner/go wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_FILENAME} @@ -88,7 +88,7 @@ not git grep -l 'x/net/context' -- "*.go" git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^interop/stress\|grpcrand\|^benchmark\|wrr_test' # - Do not use "interface{}"; use "any" instead. -git grep -l 'interface{}' -- "*.go" 2>&1 | not grep -v '\.pb\.go\|protoc-gen-go-grpc' +git grep -l 'interface{}' -- "*.go" 2>&1 | not grep -v '\.pb\.go\|protoc-gen-go-grpc\|grpc_testing_not_regenerate' # - Do not call grpclog directly. Use grpclog.Component instead. git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpclog.F' --or -e 'grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go' @@ -127,7 +127,7 @@ staticcheck -go 1.19 -checks 'all' ./... > "${SC_OUT}" || true grep -v "(ST1000)" "${SC_OUT}" | grep -v "(SA1019)" | grep -v "(ST1003)" | not grep -v "(ST1019)\|\(other import of\)" # Exclude underscore checks for generated code. -grep "(ST1003)" "${SC_OUT}" | not grep -v '\(.pb.go:\)\|\(code_string_test.go:\)' +grep "(ST1003)" "${SC_OUT}" | not grep -v '\(.pb.go:\)\|\(code_string_test.go:\)\|\(grpc_testing_not_regenerate\)' # Error for duplicate imports not including grpc protos. grep "(ST1019)\|\(other import of\)" "${SC_OUT}" | not grep -Fv 'XXXXX PleaseIgnoreUnused @@ -152,6 +152,7 @@ grep "(SA1019)" "${SC_OUT}" | not grep -Fv 'XXXXX PleaseIgnoreUnused XXXXX Protobuf related deprecation errors: "github.com/golang/protobuf .pb.go: +grpc_testing_not_regenerate : ptypes. proto.RegisterType XXXXX gRPC internal usage deprecation errors: @@ -184,9 +185,6 @@ GetSafeRegexMatch GetSuffixMatch GetTlsCertificateCertificateProviderInstance GetValidationContextCertificateProviderInstance -XXXXX TODO: Remove the below deprecation usages: -CloseNotifier -Roots.Subjects XXXXX PleaseIgnoreUnused' echo SUCCESS diff --git a/vendor/google.golang.org/protobuf/protoadapt/convert.go b/vendor/google.golang.org/protobuf/protoadapt/convert.go new file mode 100644 index 000000000..ea276d15a --- /dev/null +++ b/vendor/google.golang.org/protobuf/protoadapt/convert.go @@ -0,0 +1,31 @@ +// Copyright 2023 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 protoadapt bridges the original and new proto APIs. +package protoadapt + +import ( + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/runtime/protoiface" + "google.golang.org/protobuf/runtime/protoimpl" +) + +// MessageV1 is the original [github.com/golang/protobuf/proto.Message] type. +type MessageV1 = protoiface.MessageV1 + +// MessageV2 is the [google.golang.org/protobuf/proto.Message] type used by the +// current [google.golang.org/protobuf] module, adding support for reflection. +type MessageV2 = proto.Message + +// MessageV1Of converts a v2 message to a v1 message. +// It returns nil if m is nil. +func MessageV1Of(m MessageV2) MessageV1 { + return protoimpl.X.ProtoMessageV1Of(m) +} + +// MessageV2Of converts a v1 message to a v2 message. +// It returns nil if m is nil. +func MessageV2Of(m MessageV1) MessageV2 { + return protoimpl.X.ProtoMessageV2Of(m) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index fdac66d58..f91cdaa05 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -221,12 +221,7 @@ github.com/gofrs/flock github.com/golang-jwt/jwt/v5 # github.com/golang/protobuf v1.5.3 ## explicit; go 1.9 -github.com/golang/protobuf/jsonpb github.com/golang/protobuf/proto -github.com/golang/protobuf/ptypes -github.com/golang/protobuf/ptypes/any -github.com/golang/protobuf/ptypes/duration -github.com/golang/protobuf/ptypes/timestamp # github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 ## explicit github.com/golangci/check/cmd/structcheck @@ -938,10 +933,10 @@ golang.org/x/vuln/scan ## explicit; go 1.17 golang.org/x/xerrors golang.org/x/xerrors/internal -# google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 +# google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 ## explicit; go 1.19 google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.60.1 +# google.golang.org/grpc v1.62.1 ## explicit; go 1.19 google.golang.org/grpc google.golang.org/grpc/attributes @@ -1028,6 +1023,7 @@ google.golang.org/protobuf/internal/set google.golang.org/protobuf/internal/strs google.golang.org/protobuf/internal/version google.golang.org/protobuf/proto +google.golang.org/protobuf/protoadapt google.golang.org/protobuf/reflect/protodesc google.golang.org/protobuf/reflect/protopath google.golang.org/protobuf/reflect/protorange From 2cadba099c3ac1c87b6cd8d248fb4aa6747ab045 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 2 Apr 2024 23:42:41 +0200 Subject: [PATCH 29/31] gomod: Update google.golang.org/grpc/cmd/protoc-gen-go-grpc --- go.mod | 2 +- go.sum | 4 +- .../grpc/cmd/protoc-gen-go-grpc/grpc.go | 257 ++++++++++++------ .../grpc/cmd/protoc-gen-go-grpc/main.go | 5 +- vendor/modules.txt | 4 +- 5 files changed, 190 insertions(+), 82 deletions(-) diff --git a/go.mod b/go.mod index c3550906f..1361957ba 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( golang.org/x/text v0.14.0 golang.org/x/vuln v1.0.4 google.golang.org/grpc v1.62.1 - google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/protobuf v1.33.0 ) diff --git a/go.sum b/go.sum index df9f401f2..c81c60ba5 100644 --- a/go.sum +++ b/go.sum @@ -1118,8 +1118,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= diff --git a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go index 1e787344e..9e15d2d8d 100644 --- a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go +++ b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/grpc.go @@ -24,7 +24,7 @@ import ( "strings" "google.golang.org/protobuf/compiler/protogen" - + "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/types/descriptorpb" ) @@ -35,6 +35,94 @@ const ( statusPackage = protogen.GoImportPath("google.golang.org/grpc/status") ) +type serviceGenerateHelperInterface interface { + formatFullMethodSymbol(service *protogen.Service, method *protogen.Method) string + genFullMethods(g *protogen.GeneratedFile, service *protogen.Service) + generateClientStruct(g *protogen.GeneratedFile, clientName string) + generateNewClientDefinitions(g *protogen.GeneratedFile, service *protogen.Service, clientName string) + generateUnimplementedServerType(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service) + generateServerFunctions(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service, serverType string, serviceDescVar string) + formatHandlerFuncName(service *protogen.Service, hname string) string +} + +type serviceGenerateHelper struct{} + +func (serviceGenerateHelper) formatFullMethodSymbol(service *protogen.Service, method *protogen.Method) string { + return fmt.Sprintf("%s_%s_FullMethodName", service.GoName, method.GoName) +} + +func (serviceGenerateHelper) genFullMethods(g *protogen.GeneratedFile, service *protogen.Service) { + g.P("const (") + for _, method := range service.Methods { + fmSymbol := helper.formatFullMethodSymbol(service, method) + fmName := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name()) + g.P(fmSymbol, ` = "`, fmName, `"`) + } + g.P(")") + g.P() +} + +func (serviceGenerateHelper) generateClientStruct(g *protogen.GeneratedFile, clientName string) { + g.P("type ", unexport(clientName), " struct {") + g.P("cc ", grpcPackage.Ident("ClientConnInterface")) + g.P("}") + g.P() +} + +func (serviceGenerateHelper) generateNewClientDefinitions(g *protogen.GeneratedFile, service *protogen.Service, clientName string) { + g.P("return &", unexport(clientName), "{cc}") +} + +func (serviceGenerateHelper) generateUnimplementedServerType(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service) { + serverType := service.GoName + "Server" + mustOrShould := "must" + if !*requireUnimplemented { + mustOrShould = "should" + } + // Server Unimplemented struct for forward compatibility. + g.P("// Unimplemented", serverType, " ", mustOrShould, " be embedded to have forward compatible implementations.") + g.P("type Unimplemented", serverType, " struct {") + g.P("}") + g.P() + for _, method := range service.Methods { + nilArg := "" + if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { + nilArg = "nil," + } + g.P("func (Unimplemented", serverType, ") ", serverSignature(g, method), "{") + g.P("return ", nilArg, statusPackage.Ident("Errorf"), "(", codesPackage.Ident("Unimplemented"), `, "method `, method.GoName, ` not implemented")`) + g.P("}") + } + if *requireUnimplemented { + g.P("func (Unimplemented", serverType, ") mustEmbedUnimplemented", serverType, "() {}") + } + g.P() +} + +func (serviceGenerateHelper) generateServerFunctions(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service, serverType string, serviceDescVar string) { + // Server handler implementations. + handlerNames := make([]string, 0, len(service.Methods)) + for _, method := range service.Methods { + hname := genServerMethod(gen, file, g, method, func(hname string) string { + return hname + }) + handlerNames = append(handlerNames, hname) + } + genServiceDesc(file, g, serviceDescVar, serverType, service, handlerNames) +} + +func (serviceGenerateHelper) formatHandlerFuncName(service *protogen.Service, hname string) string { + return hname +} + +var helper serviceGenerateHelperInterface = serviceGenerateHelper{} + +// FileDescriptorProto.package field number +const fileDescriptorProtoPackageFieldNumber = 2 + +// FileDescriptorProto.syntax field number +const fileDescriptorProtoSyntaxFieldNumber = 12 + // generateFile generates a _grpc.pb.go file containing gRPC service definitions. func generateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { if len(file.Services) == 0 { @@ -42,14 +130,38 @@ func generateFile(gen *protogen.Plugin, file *protogen.File) *protogen.Generated } filename := file.GeneratedFilenamePrefix + "_grpc.pb.go" g := gen.NewGeneratedFile(filename, file.GoImportPath) + // Attach all comments associated with the syntax field. + genLeadingComments(g, file.Desc.SourceLocations().ByPath(protoreflect.SourcePath{fileDescriptorProtoSyntaxFieldNumber})) g.P("// Code generated by protoc-gen-go-grpc. DO NOT EDIT.") + g.P("// versions:") + g.P("// - protoc-gen-go-grpc v", version) + g.P("// - protoc ", protocVersion(gen)) + if file.Proto.GetOptions().GetDeprecated() { + g.P("// ", file.Desc.Path(), " is a deprecated file.") + } else { + g.P("// source: ", file.Desc.Path()) + } g.P() + // Attach all comments associated with the package field. + genLeadingComments(g, file.Desc.SourceLocations().ByPath(protoreflect.SourcePath{fileDescriptorProtoPackageFieldNumber})) g.P("package ", file.GoPackageName) g.P() generateFileContent(gen, file, g) return g } +func protocVersion(gen *protogen.Plugin) string { + v := gen.Request.GetCompilerVersion() + if v == nil { + return "(unknown)" + } + var suffix string + if s := v.GetSuffix(); s != "" { + suffix = "-" + s + } + return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(), v.GetPatch(), suffix) +} + // generateFileContent generates the gRPC service definitions, excluding the package statement. func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile) { if len(file.Services) == 0 { @@ -67,13 +179,16 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen. } func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service) { + // Full methods constants. + helper.genFullMethods(g, service) + + // Client interface. clientName := service.GoName + "Client" g.P("// ", clientName, " is the client API for ", service.GoName, " service.") g.P("//") g.P("// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.") - // Client interface. if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() { g.P("//") g.P(deprecationComment) @@ -92,17 +207,14 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated g.P() // Client structure. - g.P("type ", unexport(clientName), " struct {") - g.P("cc ", grpcPackage.Ident("ClientConnInterface")) - g.P("}") - g.P() + helper.generateClientStruct(g, clientName) // NewClient factory. if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() { g.P(deprecationComment) } g.P("func New", clientName, " (cc ", grpcPackage.Ident("ClientConnInterface"), ") ", clientName, " {") - g.P("return &", unexport(clientName), "{cc}") + helper.generateNewClientDefinitions(g, service, clientName) g.P("}") g.P() @@ -151,23 +263,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated g.P() // Server Unimplemented struct for forward compatibility. - g.P("// Unimplemented", serverType, " ", mustOrShould, " be embedded to have forward compatible implementations.") - g.P("type Unimplemented", serverType, " struct {") - g.P("}") - g.P() - for _, method := range service.Methods { - nilArg := "" - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - nilArg = "nil," - } - g.P("func (Unimplemented", serverType, ") ", serverSignature(g, method), "{") - g.P("return ", nilArg, statusPackage.Ident("Errorf"), "(", codesPackage.Ident("Unimplemented"), `, "method `, method.GoName, ` not implemented")`) - g.P("}") - } - if *requireUnimplemented { - g.P("func (Unimplemented", serverType, ") mustEmbedUnimplemented", serverType, "() {}") - } - g.P() + helper.generateUnimplementedServerType(gen, file, g, service) // Unsafe Server interface to opt-out of forward compatibility. g.P("// Unsafe", serverType, " may be embedded to opt out of forward compatibility for this service.") @@ -187,51 +283,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated g.P("}") g.P() - // Server handler implementations. - var handlerNames []string - for _, method := range service.Methods { - hname := genServerMethod(gen, file, g, method) - handlerNames = append(handlerNames, hname) - } - - // Service descriptor. - g.P("// ", serviceDescVar, " is the ", grpcPackage.Ident("ServiceDesc"), " for ", service.GoName, " service.") - g.P("// It's only intended for direct use with ", grpcPackage.Ident("RegisterService"), ",") - g.P("// and not to be introspected or modified (even as a copy)") - g.P("var ", serviceDescVar, " = ", grpcPackage.Ident("ServiceDesc"), " {") - g.P("ServiceName: ", strconv.Quote(string(service.Desc.FullName())), ",") - g.P("HandlerType: (*", serverType, ")(nil),") - g.P("Methods: []", grpcPackage.Ident("MethodDesc"), "{") - for i, method := range service.Methods { - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - continue - } - g.P("{") - g.P("MethodName: ", strconv.Quote(string(method.Desc.Name())), ",") - g.P("Handler: ", handlerNames[i], ",") - g.P("},") - } - g.P("},") - g.P("Streams: []", grpcPackage.Ident("StreamDesc"), "{") - for i, method := range service.Methods { - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - continue - } - g.P("{") - g.P("StreamName: ", strconv.Quote(string(method.Desc.Name())), ",") - g.P("Handler: ", handlerNames[i], ",") - if method.Desc.IsStreamingServer() { - g.P("ServerStreams: true,") - } - if method.Desc.IsStreamingClient() { - g.P("ClientStreams: true,") - } - g.P("},") - } - g.P("},") - g.P("Metadata: \"", file.Desc.Path(), "\",") - g.P("}") - g.P() + helper.generateServerFunctions(gen, file, g, service, serverType, serviceDescVar) } func clientSignature(g *protogen.GeneratedFile, method *protogen.Method) string { @@ -251,7 +303,7 @@ func clientSignature(g *protogen.GeneratedFile, method *protogen.Method) string func genClientMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, method *protogen.Method, index int) { service := method.Parent - sname := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name()) + fmSymbol := helper.formatFullMethodSymbol(service, method) if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() { g.P(deprecationComment) @@ -259,7 +311,7 @@ func genClientMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.Gene g.P("func (c *", unexport(service.GoName), "Client) ", clientSignature(g, method), "{") if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() { g.P("out := new(", method.Output.GoIdent, ")") - g.P(`err := c.cc.Invoke(ctx, "`, sname, `", in, out, opts...)`) + g.P(`err := c.cc.Invoke(ctx, `, fmSymbol, `, in, out, opts...)`) g.P("if err != nil { return nil, err }") g.P("return out, nil") g.P("}") @@ -268,7 +320,7 @@ func genClientMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.Gene } streamType := unexport(service.GoName) + method.GoName + "Client" serviceDescVar := service.GoName + "_ServiceDesc" - g.P("stream, err := c.cc.NewStream(ctx, &", serviceDescVar, ".Streams[", index, `], "`, sname, `", opts...)`) + g.P("stream, err := c.cc.NewStream(ctx, &", serviceDescVar, ".Streams[", index, `], `, fmSymbol, `, opts...)`) g.P("if err != nil { return nil, err }") g.P("x := &", streamType, "{stream}") if !method.Desc.IsStreamingClient() { @@ -344,18 +396,60 @@ func serverSignature(g *protogen.GeneratedFile, method *protogen.Method) string return method.GoName + "(" + strings.Join(reqArgs, ", ") + ") " + ret } -func genServerMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, method *protogen.Method) string { +func genServiceDesc(file *protogen.File, g *protogen.GeneratedFile, serviceDescVar string, serverType string, service *protogen.Service, handlerNames []string) { + // Service descriptor. + g.P("// ", serviceDescVar, " is the ", grpcPackage.Ident("ServiceDesc"), " for ", service.GoName, " service.") + g.P("// It's only intended for direct use with ", grpcPackage.Ident("RegisterService"), ",") + g.P("// and not to be introspected or modified (even as a copy)") + g.P("var ", serviceDescVar, " = ", grpcPackage.Ident("ServiceDesc"), " {") + g.P("ServiceName: ", strconv.Quote(string(service.Desc.FullName())), ",") + g.P("HandlerType: (*", serverType, ")(nil),") + g.P("Methods: []", grpcPackage.Ident("MethodDesc"), "{") + for i, method := range service.Methods { + if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { + continue + } + g.P("{") + g.P("MethodName: ", strconv.Quote(string(method.Desc.Name())), ",") + g.P("Handler: ", handlerNames[i], ",") + g.P("},") + } + g.P("},") + g.P("Streams: []", grpcPackage.Ident("StreamDesc"), "{") + for i, method := range service.Methods { + if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { + continue + } + g.P("{") + g.P("StreamName: ", strconv.Quote(string(method.Desc.Name())), ",") + g.P("Handler: ", handlerNames[i], ",") + if method.Desc.IsStreamingServer() { + g.P("ServerStreams: true,") + } + if method.Desc.IsStreamingClient() { + g.P("ClientStreams: true,") + } + g.P("},") + } + g.P("},") + g.P("Metadata: \"", file.Desc.Path(), "\",") + g.P("}") + g.P() +} + +func genServerMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, method *protogen.Method, hnameFuncNameFormatter func(string) string) string { service := method.Parent hname := fmt.Sprintf("_%s_%s_Handler", service.GoName, method.GoName) if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - g.P("func ", hname, "(srv interface{}, ctx ", contextPackage.Ident("Context"), ", dec func(interface{}) error, interceptor ", grpcPackage.Ident("UnaryServerInterceptor"), ") (interface{}, error) {") + g.P("func ", hnameFuncNameFormatter(hname), "(srv interface{}, ctx ", contextPackage.Ident("Context"), ", dec func(interface{}) error, interceptor ", grpcPackage.Ident("UnaryServerInterceptor"), ") (interface{}, error) {") g.P("in := new(", method.Input.GoIdent, ")") g.P("if err := dec(in); err != nil { return nil, err }") g.P("if interceptor == nil { return srv.(", service.GoName, "Server).", method.GoName, "(ctx, in) }") g.P("info := &", grpcPackage.Ident("UnaryServerInfo"), "{") g.P("Server: srv,") - g.P("FullMethod: ", strconv.Quote(fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name())), ",") + fmSymbol := helper.formatFullMethodSymbol(service, method) + g.P("FullMethod: ", fmSymbol, ",") g.P("}") g.P("handler := func(ctx ", contextPackage.Ident("Context"), ", req interface{}) (interface{}, error) {") g.P("return srv.(", service.GoName, "Server).", method.GoName, "(ctx, req.(*", method.Input.GoIdent, "))") @@ -366,7 +460,7 @@ func genServerMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.Gene return hname } streamType := unexport(service.GoName) + method.GoName + "Server" - g.P("func ", hname, "(srv interface{}, stream ", grpcPackage.Ident("ServerStream"), ") error {") + g.P("func ", hnameFuncNameFormatter(hname), "(srv interface{}, stream ", grpcPackage.Ident("ServerStream"), ") error {") if !method.Desc.IsStreamingClient() { g.P("m := new(", method.Input.GoIdent, ")") g.P("if err := stream.RecvMsg(m); err != nil { return err }") @@ -425,6 +519,17 @@ func genServerMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.Gene return hname } +func genLeadingComments(g *protogen.GeneratedFile, loc protoreflect.SourceLocation) { + for _, s := range loc.LeadingDetachedComments { + g.P(protogen.Comments(s)) + g.P() + } + if s := loc.LeadingComments; s != "" { + g.P(protogen.Comments(s)) + g.P() + } +} + const deprecationComment = "// Deprecated: Do not use." func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] } diff --git a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go index 7f104da7d..340eaf3ee 100644 --- a/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go +++ b/vendor/google.golang.org/grpc/cmd/protoc-gen-go-grpc/main.go @@ -19,14 +19,17 @@ // protoc-gen-go-grpc is a plugin for the Google protocol buffer compiler to // generate Go code. Install it by building this program and making it // accessible within your PATH with the name: +// // protoc-gen-go-grpc // // The 'go-grpc' suffix becomes part of the argument for the protocol compiler, // such that it can be invoked as: +// // protoc --go-grpc_out=. path/to/file.proto // // This generates Go service definitions for the protocol buffer defined by // file.proto. With that input, the output will be written to: +// // path/to/file_grpc.pb.go package main @@ -38,7 +41,7 @@ import ( "google.golang.org/protobuf/types/pluginpb" ) -const version = "1.1.0" +const version = "1.3.0" var requireUnimplemented *bool diff --git a/vendor/modules.txt b/vendor/modules.txt index f91cdaa05..c4dd94621 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -989,8 +989,8 @@ google.golang.org/grpc/serviceconfig google.golang.org/grpc/stats google.golang.org/grpc/status google.golang.org/grpc/tap -# google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 -## explicit; go 1.9 +# google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 +## explicit; go 1.17 google.golang.org/grpc/cmd/protoc-gen-go-grpc # google.golang.org/protobuf v1.33.0 ## explicit; go 1.17 From e34acf7e335c87072d937e50a1786ab382a7e85f Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 9 Apr 2024 23:03:42 +0200 Subject: [PATCH 30/31] gomod: Update go-pg to v10 --- go.mod | 11 +- go.sum | 30 +- vendor/github.com/go-pg/pg/.travis.yml | 23 - vendor/github.com/go-pg/pg/CHANGELOG.md | 70 - vendor/github.com/go-pg/pg/README.md | 167 -- vendor/github.com/go-pg/pg/db.go | 517 ----- vendor/github.com/go-pg/pg/doc.go | 4 - vendor/github.com/go-pg/pg/hook.go | 145 -- .../github.com/go-pg/pg/internal/internal.go | 24 - vendor/github.com/go-pg/pg/internal/log.go | 15 - .../go-pg/pg/internal/parser/array_parser.go | 92 - .../pg/internal/parser/composite_parser.go | 53 - .../go-pg/pg/internal/parser/hstore_parser.go | 40 - .../go-pg/pg/internal/parser/parser.go | 170 -- .../go-pg/pg/internal/parser/util.go | 15 - .../github.com/go-pg/pg/internal/pool/conn.go | 129 -- .../go-pg/pg/internal/pool/elastic_reader.go | 185 -- .../go-pg/pg/internal/pool/pool_single.go | 53 - .../go-pg/pg/internal/pool/reader.go | 71 - vendor/github.com/go-pg/pg/listener.go | 316 ---- vendor/github.com/go-pg/pg/orm/composite.go | 56 - .../go-pg/pg/orm/composite_create.go | 68 - .../github.com/go-pg/pg/orm/composite_drop.go | 50 - vendor/github.com/go-pg/pg/orm/delete.go | 83 - vendor/github.com/go-pg/pg/orm/field.go | 108 -- vendor/github.com/go-pg/pg/orm/format.go | 286 --- vendor/github.com/go-pg/pg/orm/hook.go | 199 -- vendor/github.com/go-pg/pg/orm/inflection.go | 17 - vendor/github.com/go-pg/pg/orm/insert.go | 157 -- vendor/github.com/go-pg/pg/orm/model.go | 110 -- .../github.com/go-pg/pg/orm/model_discard.go | 23 - vendor/github.com/go-pg/pg/orm/model_slice.go | 35 - vendor/github.com/go-pg/pg/orm/model_table.go | 109 -- .../go-pg/pg/orm/model_table_m2m.go | 135 -- .../go-pg/pg/orm/model_table_many.go | 113 -- .../go-pg/pg/orm/model_table_slice.go | 152 -- vendor/github.com/go-pg/pg/orm/orm.go | 46 - vendor/github.com/go-pg/pg/orm/pager.go | 111 -- vendor/github.com/go-pg/pg/orm/query.go | 1302 ------------- vendor/github.com/go-pg/pg/orm/select.go | 201 -- vendor/github.com/go-pg/pg/orm/table.go | 891 --------- .../github.com/go-pg/pg/orm/table_create.go | 155 -- vendor/github.com/go-pg/pg/orm/table_drop.go | 50 - vendor/github.com/go-pg/pg/orm/update.go | 257 --- vendor/github.com/go-pg/pg/orm/url_filter.go | 114 -- vendor/github.com/go-pg/pg/orm/url_values.go | 106 -- vendor/github.com/go-pg/pg/pg.go | 209 -- vendor/github.com/go-pg/pg/stmt.go | 278 --- vendor/github.com/go-pg/pg/tx.go | 338 ---- vendor/github.com/go-pg/pg/types/append.go | 202 -- .../github.com/go-pg/pg/types/append_array.go | 190 -- .../github.com/go-pg/pg/types/append_field.go | 52 - .../github.com/go-pg/pg/types/append_jsonb.go | 41 - .../github.com/go-pg/pg/types/append_value.go | 181 -- vendor/github.com/go-pg/pg/types/array.go | 52 - vendor/github.com/go-pg/pg/types/hstore.go | 52 - vendor/github.com/go-pg/pg/types/in_op.go | 49 - vendor/github.com/go-pg/pg/types/interface.go | 27 - vendor/github.com/go-pg/pg/types/scan.go | 83 - .../github.com/go-pg/pg/types/scan_array.go | 197 -- .../github.com/go-pg/pg/types/scan_value.go | 304 --- vendor/github.com/go-pg/pg/v10/.golangci.yml | 18 + vendor/github.com/go-pg/pg/v10/.prettierrc | 4 + vendor/github.com/go-pg/pg/v10/CHANGELOG.md | 242 +++ vendor/github.com/go-pg/pg/{ => v10}/LICENSE | 0 vendor/github.com/go-pg/pg/v10/Makefile | 32 + vendor/github.com/go-pg/pg/v10/README.md | 248 +++ vendor/github.com/go-pg/pg/v10/base.go | 624 ++++++ vendor/github.com/go-pg/pg/v10/db.go | 142 ++ vendor/github.com/go-pg/pg/v10/doc.go | 4 + vendor/github.com/go-pg/pg/{ => v10}/error.go | 43 +- vendor/github.com/go-pg/pg/v10/hook.go | 139 ++ .../go-pg/pg/v10/internal/context.go | 26 + .../go-pg/pg/{ => v10}/internal/error.go | 6 +- .../go-pg/pg/v10/internal/internal.go | 27 + .../github.com/go-pg/pg/v10/internal/log.go | 28 + .../go-pg/pg/v10/internal/parser/parser.go | 141 ++ .../v10/internal/parser/streaming_parser.go | 65 + .../go-pg/pg/v10/internal/pool/conn.go | 158 ++ .../go-pg/pg/{ => v10}/internal/pool/pool.go | 208 +- .../go-pg/pg/v10/internal/pool/pool_single.go | 63 + .../go-pg/pg/v10/internal/pool/pool_sticky.go | 202 ++ .../go-pg/pg/v10/internal/pool/reader.go | 80 + .../go-pg/pg/v10/internal/pool/reader_buf.go | 431 +++++ .../pg/v10/internal/pool/reader_bytes.go | 121 ++ .../{ => v10}/internal/pool/write_buffer.go | 40 +- .../github.com/go-pg/pg/v10/internal/safe.go | 12 + .../go-pg/pg/{ => v10}/internal/strconv.go | 0 .../go-pg/pg/{ => v10}/internal/underscore.go | 0 .../go-pg/pg/v10/internal/unsafe.go | 23 + .../go-pg/pg/{ => v10}/internal/util.go | 37 +- vendor/github.com/go-pg/pg/v10/listener.go | 416 ++++ .../github.com/go-pg/pg/{ => v10}/messages.go | 622 ++++-- .../github.com/go-pg/pg/{ => v10}/options.go | 184 +- .../github.com/go-pg/pg/v10/orm/composite.go | 100 + .../go-pg/pg/v10/orm/composite_create.go | 89 + .../go-pg/pg/v10/orm/composite_drop.go | 70 + .../go-pg/pg/v10/orm/composite_parser.go | 140 ++ .../go-pg/pg/{ => v10}/orm/count_estimate.go | 15 +- vendor/github.com/go-pg/pg/v10/orm/delete.go | 158 ++ vendor/github.com/go-pg/pg/v10/orm/field.go | 147 ++ vendor/github.com/go-pg/pg/v10/orm/format.go | 333 ++++ vendor/github.com/go-pg/pg/v10/orm/hook.go | 248 +++ vendor/github.com/go-pg/pg/v10/orm/insert.go | 345 ++++ .../github.com/go-pg/pg/{ => v10}/orm/join.go | 158 +- vendor/github.com/go-pg/pg/v10/orm/model.go | 150 ++ .../go-pg/pg/v10/orm/model_discard.go | 27 + .../go-pg/pg/{ => v10}/orm/model_func.go | 4 +- .../github.com/go-pg/pg/v10/orm/model_map.go | 53 + .../go-pg/pg/v10/orm/model_map_slice.go | 45 + .../go-pg/pg/{ => v10}/orm/model_scan.go | 23 +- .../go-pg/pg/v10/orm/model_slice.go | 43 + .../go-pg/pg/v10/orm/model_table.go | 65 + .../go-pg/pg/v10/orm/model_table_m2m.go | 111 ++ .../go-pg/pg/v10/orm/model_table_many.go | 75 + .../go-pg/pg/v10/orm/model_table_slice.go | 156 ++ .../pg/{ => v10}/orm/model_table_struct.go | 188 +- vendor/github.com/go-pg/pg/v10/orm/msgpack.go | 52 + vendor/github.com/go-pg/pg/v10/orm/orm.go | 58 + vendor/github.com/go-pg/pg/v10/orm/query.go | 1685 +++++++++++++++++ .../go-pg/pg/{ => v10}/orm/relation.go | 17 +- .../go-pg/pg/{ => v10}/orm/result.go | 2 +- vendor/github.com/go-pg/pg/v10/orm/select.go | 346 ++++ vendor/github.com/go-pg/pg/v10/orm/table.go | 1580 ++++++++++++++++ .../go-pg/pg/v10/orm/table_create.go | 248 +++ .../github.com/go-pg/pg/v10/orm/table_drop.go | 73 + .../go-pg/pg/{ => v10}/orm/table_params.go | 2 +- .../go-pg/pg/{ => v10}/orm/tables.go | 104 +- vendor/github.com/go-pg/pg/v10/orm/types.go | 48 + vendor/github.com/go-pg/pg/v10/orm/update.go | 378 ++++ .../github.com/go-pg/pg/{ => v10}/orm/util.go | 58 +- vendor/github.com/go-pg/pg/v10/pg.go | 274 +++ vendor/github.com/go-pg/pg/v10/pgjson/json.go | 26 + .../go-pg/pg/v10/pgjson/provider.go | 43 + .../github.com/go-pg/pg/{ => v10}/result.go | 10 +- vendor/github.com/go-pg/pg/v10/stmt.go | 282 +++ vendor/github.com/go-pg/pg/v10/tx.go | 388 ++++ .../github.com/go-pg/pg/v10/types/append.go | 203 ++ .../go-pg/pg/v10/types/append_ident.go | 46 + .../go-pg/pg/v10/types/append_jsonb.go | 49 + .../go-pg/pg/v10/types/append_value.go | 248 +++ vendor/github.com/go-pg/pg/v10/types/array.go | 58 + .../go-pg/pg/v10/types/array_append.go | 236 +++ .../go-pg/pg/v10/types/array_parser.go | 170 ++ .../go-pg/pg/v10/types/array_scan.go | 334 ++++ .../github.com/go-pg/pg/v10/types/column.go | 113 ++ vendor/github.com/go-pg/pg/v10/types/doc.go | 4 + vendor/github.com/go-pg/pg/v10/types/flags.go | 25 + vendor/github.com/go-pg/pg/v10/types/hex.go | 81 + .../github.com/go-pg/pg/v10/types/hstore.go | 59 + .../types/hstore_append.go} | 19 +- .../go-pg/pg/v10/types/hstore_parser.go | 65 + .../types/hstore_scan.go} | 43 +- vendor/github.com/go-pg/pg/v10/types/in_op.go | 62 + .../pg/{time.go => v10/types/null_time.go} | 22 +- vendor/github.com/go-pg/pg/v10/types/scan.go | 244 +++ .../go-pg/pg/v10/types/scan_value.go | 418 ++++ .../go-pg/pg/{ => v10}/types/time.go | 8 +- vendor/github.com/go-pg/pg/v10/types/types.go | 37 + vendor/github.com/go-pg/pg/v10/version.go | 6 + vendor/github.com/go-pg/zerochecker/LICENSE | 24 + .../zero.go => zerochecker/zerochecker.go} | 37 +- vendor/github.com/tmthrgd/go-hex/.travis.yml | 11 + vendor/github.com/tmthrgd/go-hex/LICENSE | 82 + vendor/github.com/tmthrgd/go-hex/README.md | 108 ++ vendor/github.com/tmthrgd/go-hex/hex.go | 137 ++ vendor/github.com/tmthrgd/go-hex/hex_amd64.go | 94 + .../tmthrgd/go-hex/hex_decode_amd64.s | 303 +++ .../tmthrgd/go-hex/hex_encode_amd64.s | 227 +++ vendor/github.com/tmthrgd/go-hex/hex_other.go | 36 + .../vmihailenco/bufpool/.travis.yml | 20 + vendor/github.com/vmihailenco/bufpool/LICENSE | 23 + .../pg => vmihailenco/bufpool}/Makefile | 3 +- .../github.com/vmihailenco/bufpool/README.md | 74 + .../vmihailenco/bufpool/buf_pool.go | 67 + .../github.com/vmihailenco/bufpool/buffer.go | 397 ++++ .../vmihailenco/bufpool/buffer_ext.go | 66 + vendor/github.com/vmihailenco/bufpool/pool.go | 148 ++ .../vmihailenco/msgpack/v5/.golangci.yml | 18 + .../vmihailenco/msgpack/v5/.prettierrc | 4 + .../vmihailenco/msgpack/v5/.travis.yml | 20 + .../vmihailenco/msgpack/v5/CHANGELOG.md | 3 + .../github.com/vmihailenco/msgpack/v5/LICENSE | 25 + .../vmihailenco/msgpack/v5/Makefile | 7 + .../vmihailenco/msgpack/v5/README.md | 85 + .../vmihailenco/msgpack/v5/decode.go | 660 +++++++ .../vmihailenco/msgpack/v5/decode_map.go | 339 ++++ .../vmihailenco/msgpack/v5/decode_number.go | 295 +++ .../vmihailenco/msgpack/v5/decode_query.go | 158 ++ .../vmihailenco/msgpack/v5/decode_slice.go | 191 ++ .../vmihailenco/msgpack/v5/decode_string.go | 192 ++ .../vmihailenco/msgpack/v5/decode_value.go | 250 +++ .../vmihailenco/msgpack/v5/encode.go | 269 +++ .../vmihailenco/msgpack/v5/encode_map.go | 178 ++ .../vmihailenco/msgpack/v5/encode_number.go | 252 +++ .../vmihailenco/msgpack/v5/encode_slice.go | 139 ++ .../vmihailenco/msgpack/v5/encode_value.go | 245 +++ .../github.com/vmihailenco/msgpack/v5/ext.go | 303 +++ .../vmihailenco/msgpack/v5/intern.go | 238 +++ .../vmihailenco/msgpack/v5/msgpack.go | 52 + .../msgpack/v5/msgpcode/msgpcode.go | 88 + .../github.com/vmihailenco/msgpack/v5/safe.go | 13 + .../github.com/vmihailenco/msgpack/v5/time.go | 145 ++ .../vmihailenco/msgpack/v5/types.go | 407 ++++ .../vmihailenco/msgpack/v5/unsafe.go | 22 + .../vmihailenco/tagparser/.travis.yml | 24 + .../github.com/vmihailenco/tagparser/LICENSE | 25 + .../github.com/vmihailenco/tagparser/Makefile | 8 + .../vmihailenco/tagparser/README.md | 24 + .../tagparser/internal/parser/parser.go | 82 + .../tagparser}/internal/safe.go | 0 .../tagparser}/internal/unsafe.go | 0 .../tagparser/tagparser.go} | 62 +- .../vmihailenco/tagparser/v2/.travis.yml | 19 + .../vmihailenco/tagparser/v2/LICENSE | 25 + .../vmihailenco/tagparser/v2/Makefile | 9 + .../vmihailenco/tagparser/v2/README.md | 24 + .../tagparser/v2/internal/parser/parser.go | 82 + .../vmihailenco/tagparser/v2/internal/safe.go | 11 + .../tagparser/v2/internal/unsafe.go | 22 + .../vmihailenco/tagparser/v2/tagparser.go | 166 ++ vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 + vendor/mellium.im/sasl/.gitignore | 6 + vendor/mellium.im/sasl/CHANGELOG.md | 28 + vendor/mellium.im/sasl/DCO | 37 + vendor/mellium.im/sasl/LICENSE | 23 + vendor/mellium.im/sasl/README.md | 21 + vendor/mellium.im/sasl/doc.go | 15 + vendor/mellium.im/sasl/mechanism.go | 61 + vendor/mellium.im/sasl/negotiator.go | 196 ++ vendor/mellium.im/sasl/nonce.go | 30 + vendor/mellium.im/sasl/options.go | 61 + vendor/mellium.im/sasl/plain.go | 52 + vendor/mellium.im/sasl/scram.go | 286 +++ vendor/mellium.im/sasl/xor.go | 26 + vendor/mellium.im/sasl/xor_amd64.go | 10 + vendor/mellium.im/sasl/xor_amd64.s | 56 + vendor/mellium.im/sasl/xor_arm64.go | 10 + vendor/mellium.im/sasl/xor_arm64.s | 69 + vendor/mellium.im/sasl/xor_generic.go | 58 + vendor/mellium.im/sasl/xor_go.go | 15 + vendor/mellium.im/sasl/xor_ppc64x.go | 10 + vendor/mellium.im/sasl/xor_ppc64x.s | 87 + vendor/modules.txt | 46 +- 244 files changed, 23045 insertions(+), 9945 deletions(-) delete mode 100644 vendor/github.com/go-pg/pg/.travis.yml delete mode 100644 vendor/github.com/go-pg/pg/CHANGELOG.md delete mode 100644 vendor/github.com/go-pg/pg/README.md delete mode 100644 vendor/github.com/go-pg/pg/db.go delete mode 100644 vendor/github.com/go-pg/pg/doc.go delete mode 100644 vendor/github.com/go-pg/pg/hook.go delete mode 100644 vendor/github.com/go-pg/pg/internal/internal.go delete mode 100644 vendor/github.com/go-pg/pg/internal/log.go delete mode 100644 vendor/github.com/go-pg/pg/internal/parser/array_parser.go delete mode 100644 vendor/github.com/go-pg/pg/internal/parser/composite_parser.go delete mode 100644 vendor/github.com/go-pg/pg/internal/parser/hstore_parser.go delete mode 100644 vendor/github.com/go-pg/pg/internal/parser/parser.go delete mode 100644 vendor/github.com/go-pg/pg/internal/parser/util.go delete mode 100644 vendor/github.com/go-pg/pg/internal/pool/conn.go delete mode 100644 vendor/github.com/go-pg/pg/internal/pool/elastic_reader.go delete mode 100644 vendor/github.com/go-pg/pg/internal/pool/pool_single.go delete mode 100644 vendor/github.com/go-pg/pg/internal/pool/reader.go delete mode 100644 vendor/github.com/go-pg/pg/listener.go delete mode 100644 vendor/github.com/go-pg/pg/orm/composite.go delete mode 100644 vendor/github.com/go-pg/pg/orm/composite_create.go delete mode 100644 vendor/github.com/go-pg/pg/orm/composite_drop.go delete mode 100644 vendor/github.com/go-pg/pg/orm/delete.go delete mode 100644 vendor/github.com/go-pg/pg/orm/field.go delete mode 100644 vendor/github.com/go-pg/pg/orm/format.go delete mode 100644 vendor/github.com/go-pg/pg/orm/hook.go delete mode 100644 vendor/github.com/go-pg/pg/orm/inflection.go delete mode 100644 vendor/github.com/go-pg/pg/orm/insert.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model_discard.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model_slice.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model_table.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model_table_m2m.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model_table_many.go delete mode 100644 vendor/github.com/go-pg/pg/orm/model_table_slice.go delete mode 100644 vendor/github.com/go-pg/pg/orm/orm.go delete mode 100644 vendor/github.com/go-pg/pg/orm/pager.go delete mode 100644 vendor/github.com/go-pg/pg/orm/query.go delete mode 100644 vendor/github.com/go-pg/pg/orm/select.go delete mode 100644 vendor/github.com/go-pg/pg/orm/table.go delete mode 100644 vendor/github.com/go-pg/pg/orm/table_create.go delete mode 100644 vendor/github.com/go-pg/pg/orm/table_drop.go delete mode 100644 vendor/github.com/go-pg/pg/orm/update.go delete mode 100644 vendor/github.com/go-pg/pg/orm/url_filter.go delete mode 100644 vendor/github.com/go-pg/pg/orm/url_values.go delete mode 100644 vendor/github.com/go-pg/pg/pg.go delete mode 100644 vendor/github.com/go-pg/pg/stmt.go delete mode 100644 vendor/github.com/go-pg/pg/tx.go delete mode 100644 vendor/github.com/go-pg/pg/types/append.go delete mode 100644 vendor/github.com/go-pg/pg/types/append_array.go delete mode 100644 vendor/github.com/go-pg/pg/types/append_field.go delete mode 100644 vendor/github.com/go-pg/pg/types/append_jsonb.go delete mode 100644 vendor/github.com/go-pg/pg/types/append_value.go delete mode 100644 vendor/github.com/go-pg/pg/types/array.go delete mode 100644 vendor/github.com/go-pg/pg/types/hstore.go delete mode 100644 vendor/github.com/go-pg/pg/types/in_op.go delete mode 100644 vendor/github.com/go-pg/pg/types/interface.go delete mode 100644 vendor/github.com/go-pg/pg/types/scan.go delete mode 100644 vendor/github.com/go-pg/pg/types/scan_array.go delete mode 100644 vendor/github.com/go-pg/pg/types/scan_value.go create mode 100644 vendor/github.com/go-pg/pg/v10/.golangci.yml create mode 100644 vendor/github.com/go-pg/pg/v10/.prettierrc create mode 100644 vendor/github.com/go-pg/pg/v10/CHANGELOG.md rename vendor/github.com/go-pg/pg/{ => v10}/LICENSE (100%) create mode 100644 vendor/github.com/go-pg/pg/v10/Makefile create mode 100644 vendor/github.com/go-pg/pg/v10/README.md create mode 100644 vendor/github.com/go-pg/pg/v10/base.go create mode 100644 vendor/github.com/go-pg/pg/v10/db.go create mode 100644 vendor/github.com/go-pg/pg/v10/doc.go rename vendor/github.com/go-pg/pg/{ => v10}/error.go (58%) create mode 100644 vendor/github.com/go-pg/pg/v10/hook.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/context.go rename vendor/github.com/go-pg/pg/{ => v10}/internal/error.go (87%) create mode 100644 vendor/github.com/go-pg/pg/v10/internal/internal.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/log.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/parser/parser.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/pool/conn.go rename vendor/github.com/go-pg/pg/{ => v10}/internal/pool/pool.go (75%) create mode 100644 vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/pool/reader.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go create mode 100644 vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go rename vendor/github.com/go-pg/pg/{ => v10}/internal/pool/write_buffer.go (78%) create mode 100644 vendor/github.com/go-pg/pg/v10/internal/safe.go rename vendor/github.com/go-pg/pg/{ => v10}/internal/strconv.go (100%) rename vendor/github.com/go-pg/pg/{ => v10}/internal/underscore.go (100%) create mode 100644 vendor/github.com/go-pg/pg/v10/internal/unsafe.go rename vendor/github.com/go-pg/pg/{ => v10}/internal/util.go (60%) create mode 100644 vendor/github.com/go-pg/pg/v10/listener.go rename vendor/github.com/go-pg/pg/{ => v10}/messages.go (56%) rename vendor/github.com/go-pg/pg/{ => v10}/options.go (58%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/composite.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/composite_create.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/composite_drop.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/composite_parser.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/count_estimate.go (83%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/delete.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/field.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/format.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/hook.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/insert.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/join.go (63%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_discard.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/model_func.go (91%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_map.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_map_slice.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/model_scan.go (59%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_slice.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_table.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_table_m2m.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_table_many.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/model_table_slice.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/model_table_struct.go (52%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/msgpack.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/orm.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/query.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/relation.go (57%) rename vendor/github.com/go-pg/pg/{ => v10}/orm/result.go (88%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/select.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/table.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/table_create.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/table_drop.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/table_params.go (81%) rename vendor/github.com/go-pg/pg/{ => v10}/orm/tables.go (51%) create mode 100644 vendor/github.com/go-pg/pg/v10/orm/types.go create mode 100644 vendor/github.com/go-pg/pg/v10/orm/update.go rename vendor/github.com/go-pg/pg/{ => v10}/orm/util.go (61%) create mode 100644 vendor/github.com/go-pg/pg/v10/pg.go create mode 100644 vendor/github.com/go-pg/pg/v10/pgjson/json.go create mode 100644 vendor/github.com/go-pg/pg/v10/pgjson/provider.go rename vendor/github.com/go-pg/pg/{ => v10}/result.go (77%) create mode 100644 vendor/github.com/go-pg/pg/v10/stmt.go create mode 100644 vendor/github.com/go-pg/pg/v10/tx.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/append.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/append_ident.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/append_jsonb.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/append_value.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/array.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/array_append.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/array_parser.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/array_scan.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/column.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/doc.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/flags.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/hex.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/hstore.go rename vendor/github.com/go-pg/pg/{types/append_hstore.go => v10/types/hstore_append.go} (63%) create mode 100644 vendor/github.com/go-pg/pg/v10/types/hstore_parser.go rename vendor/github.com/go-pg/pg/{types/scan_hstore.go => v10/types/hstore_scan.go} (51%) create mode 100644 vendor/github.com/go-pg/pg/v10/types/in_op.go rename vendor/github.com/go-pg/pg/{time.go => v10/types/null_time.go} (64%) create mode 100644 vendor/github.com/go-pg/pg/v10/types/scan.go create mode 100644 vendor/github.com/go-pg/pg/v10/types/scan_value.go rename vendor/github.com/go-pg/pg/{ => v10}/types/time.go (90%) create mode 100644 vendor/github.com/go-pg/pg/v10/types/types.go create mode 100644 vendor/github.com/go-pg/pg/v10/version.go create mode 100644 vendor/github.com/go-pg/zerochecker/LICENSE rename vendor/github.com/go-pg/{pg/orm/zero.go => zerochecker/zerochecker.go} (74%) create mode 100644 vendor/github.com/tmthrgd/go-hex/.travis.yml create mode 100644 vendor/github.com/tmthrgd/go-hex/LICENSE create mode 100644 vendor/github.com/tmthrgd/go-hex/README.md create mode 100644 vendor/github.com/tmthrgd/go-hex/hex.go create mode 100644 vendor/github.com/tmthrgd/go-hex/hex_amd64.go create mode 100644 vendor/github.com/tmthrgd/go-hex/hex_decode_amd64.s create mode 100644 vendor/github.com/tmthrgd/go-hex/hex_encode_amd64.s create mode 100644 vendor/github.com/tmthrgd/go-hex/hex_other.go create mode 100644 vendor/github.com/vmihailenco/bufpool/.travis.yml create mode 100644 vendor/github.com/vmihailenco/bufpool/LICENSE rename vendor/github.com/{go-pg/pg => vmihailenco/bufpool}/Makefile (58%) create mode 100644 vendor/github.com/vmihailenco/bufpool/README.md create mode 100644 vendor/github.com/vmihailenco/bufpool/buf_pool.go create mode 100644 vendor/github.com/vmihailenco/bufpool/buffer.go create mode 100644 vendor/github.com/vmihailenco/bufpool/buffer_ext.go create mode 100644 vendor/github.com/vmihailenco/bufpool/pool.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/.golangci.yml create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/.prettierrc create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/.travis.yml create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/CHANGELOG.md create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/LICENSE create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/Makefile create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/README.md create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode_map.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode_number.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode_query.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode_slice.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode_string.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/decode_value.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/encode.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/encode_map.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/encode_number.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/encode_slice.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/encode_value.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/ext.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/intern.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/msgpack.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/msgpcode/msgpcode.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/safe.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/time.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/types.go create mode 100644 vendor/github.com/vmihailenco/msgpack/v5/unsafe.go create mode 100644 vendor/github.com/vmihailenco/tagparser/.travis.yml create mode 100644 vendor/github.com/vmihailenco/tagparser/LICENSE create mode 100644 vendor/github.com/vmihailenco/tagparser/Makefile create mode 100644 vendor/github.com/vmihailenco/tagparser/README.md create mode 100644 vendor/github.com/vmihailenco/tagparser/internal/parser/parser.go rename vendor/github.com/{go-pg/pg => vmihailenco/tagparser}/internal/safe.go (100%) rename vendor/github.com/{go-pg/pg => vmihailenco/tagparser}/internal/unsafe.go (100%) rename vendor/github.com/{go-pg/pg/orm/tag.go => vmihailenco/tagparser/tagparser.go} (66%) create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/.travis.yml create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/LICENSE create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/Makefile create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/README.md create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/internal/parser/parser.go create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/internal/safe.go create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/internal/unsafe.go create mode 100644 vendor/github.com/vmihailenco/tagparser/v2/tagparser.go create mode 100644 vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 vendor/mellium.im/sasl/.gitignore create mode 100644 vendor/mellium.im/sasl/CHANGELOG.md create mode 100644 vendor/mellium.im/sasl/DCO create mode 100644 vendor/mellium.im/sasl/LICENSE create mode 100644 vendor/mellium.im/sasl/README.md create mode 100644 vendor/mellium.im/sasl/doc.go create mode 100644 vendor/mellium.im/sasl/mechanism.go create mode 100644 vendor/mellium.im/sasl/negotiator.go create mode 100644 vendor/mellium.im/sasl/nonce.go create mode 100644 vendor/mellium.im/sasl/options.go create mode 100644 vendor/mellium.im/sasl/plain.go create mode 100644 vendor/mellium.im/sasl/scram.go create mode 100644 vendor/mellium.im/sasl/xor.go create mode 100644 vendor/mellium.im/sasl/xor_amd64.go create mode 100644 vendor/mellium.im/sasl/xor_amd64.s create mode 100644 vendor/mellium.im/sasl/xor_arm64.go create mode 100644 vendor/mellium.im/sasl/xor_arm64.s create mode 100644 vendor/mellium.im/sasl/xor_generic.go create mode 100644 vendor/mellium.im/sasl/xor_go.go create mode 100644 vendor/mellium.im/sasl/xor_ppc64x.go create mode 100644 vendor/mellium.im/sasl/xor_ppc64x.s diff --git a/go.mod b/go.mod index 1361957ba..2d2acee56 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/getkin/kin-openapi v0.0.0-20180813063848-e1956e8013e5 github.com/go-kivik/couchdb/v3 v3.2.6 github.com/go-kivik/kivik/v3 v3.2.3 - github.com/go-pg/pg v6.14.5+incompatible + github.com/go-pg/pg/v10 v10.12.0 github.com/go-redis/redis/v7 v7.4.1 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golangci/golangci-lint v1.51.2 @@ -86,6 +86,7 @@ require ( github.com/fzipp/gocyclo v0.6.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-critic/go-critic v0.6.7 // indirect + github.com/go-pg/zerochecker v0.2.0 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.0.3 // indirect github.com/go-toolsmith/astequal v1.1.0 // indirect @@ -121,7 +122,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jgautheron/goconst v1.5.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect - github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect + github.com/jinzhu/inflection v1.0.0 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/julz/importas v0.1.0 // indirect @@ -195,12 +196,17 @@ require ( github.com/tetafro/godot v1.4.11 // indirect github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e // indirect github.com/timonwong/loggercheck v0.9.3 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/tomarrell/wrapcheck/v2 v2.8.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/uber-go/atomic v1.3.2 // indirect github.com/ultraware/funlen v0.0.3 // indirect github.com/ultraware/whitespace v0.0.5 // indirect github.com/uudashr/gocognit v1.0.6 // indirect + github.com/vmihailenco/bufpool v0.1.11 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect + github.com/vmihailenco/tagparser v0.1.2 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.2.0 // indirect gitlab.com/bosi/decorder v0.2.3 // indirect @@ -221,6 +227,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.4.2 // indirect + mellium.im/sasl v0.3.1 // indirect mvdan.cc/gofumpt v0.4.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect diff --git a/go.sum b/go.sum index c81c60ba5..c5c1ea51b 100644 --- a/go.sum +++ b/go.sum @@ -192,8 +192,10 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-pg/pg v6.14.5+incompatible h1:Tc74MTCCIVd8sAJshYHqutcHhO64/EBHBTydzCGt3Js= -github.com/go-pg/pg v6.14.5+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA= +github.com/go-pg/pg/v10 v10.12.0 h1:rBmfDDHTN7FQW0OemYmcn5UuBy6wkYWgh/Oqt1OBEB8= +github.com/go-pg/pg/v10 v10.12.0/go.mod h1:USA08CdIasAn0F6wC1nBf5nQhMHewVQodWoH89RPXaI= +github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU= +github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo= github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI= github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= @@ -360,7 +362,6 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -370,8 +371,8 @@ github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+ github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k= -github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -486,12 +487,15 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.8.1 h1:/y4o/0hV+ruUHj4xXh89xlFjoaitnI4LnkpuYs02q1c= github.com/nunnatsa/ginkgolinter v0.8.1/go.mod h1:FYYLtszIdmzCH8XMaMPyxPVXZ7VCaIm55bA+gugx+14= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI= github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -633,6 +637,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf 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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -655,6 +660,8 @@ github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e h1:MV6KaVu/hzByH github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI= github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/tomarrell/wrapcheck/v2 v2.8.0 h1:qDzbir0xmoE+aNxGCPrn+rUSxAX+nG6vREgbbXAR81I= github.com/tomarrell/wrapcheck/v2 v2.8.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= @@ -671,6 +678,14 @@ github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqz github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y= github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= +github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94= +github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ= +github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= +github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o= @@ -1142,7 +1157,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -1170,6 +1184,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc= honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= +mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= +mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= diff --git a/vendor/github.com/go-pg/pg/.travis.yml b/vendor/github.com/go-pg/pg/.travis.yml deleted file mode 100644 index 5ae69b823..000000000 --- a/vendor/github.com/go-pg/pg/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -dist: trusty -language: go - -addons: - postgresql: "9.6" - -go: - - 1.9.x - - 1.10.x - - tip - -matrix: - allow_failures: - - go: tip - -before_install: - - psql -U postgres -c "CREATE EXTENSION hstore" - -install: - - go get github.com/jinzhu/inflection - - go get gopkg.in/check.v1 - - go get github.com/onsi/ginkgo - - go get github.com/onsi/gomega diff --git a/vendor/github.com/go-pg/pg/CHANGELOG.md b/vendor/github.com/go-pg/pg/CHANGELOG.md deleted file mode 100644 index e99e449e2..000000000 --- a/vendor/github.com/go-pg/pg/CHANGELOG.md +++ /dev/null @@ -1,70 +0,0 @@ -# Changelog - -## Unreleased - -- Added Options.MinIdleConns. -- Options.MaxAge renamed to Options.MaxConnAge. -- PoolStats.FreeConns is renamed to PoolStats.IdleConns. -- New hook BeforeSelectQuery. -- `,override` is renamed to `,inherit`. - -## v6.15 - -- Dialer.KeepAlive is set to 5 minutes by default. - -## v6.14 - -- Fields ignored with `sql:"-"` tag are no longer considered by ORM relation detector. - -## v6.12 - -- `Insert`, `Update`, and `Delete` can return `pg.ErrNoRows` and `pg.ErrMultiRows` when `Returning` is used and model expects single row. - -## v6.11 - -- `db.Model(&strct).Update()` and `db.Model(&strct).Delete()` no longer adds WHERE condition based on primary key when there are no conditions. Instead you should use `db.Update(&strct)` or `db.Model(&strct).WherePK().Update()`. - -## v6.10 - -- `?Columns` is renamed to `?TableColumns`. `?Columns` is changed to produce column names without table alias. - -## v6.9 - -- `pg:"fk"` tag now accepts SQL names instead of Go names, e.g. `pg:"fk:ParentId"` becomes `pg:"fk:parent_id"`. Old code should continue working in most cases, but it is strongly advised to start using new convention. -- uint and uint64 SQL type is changed from decimal to bigint according to the the lesser of two evils principle. Use `sql:"type:decimal"` to get old behavior. - -## v6.8 - -- `CreateTable` no longer adds ON DELETE hook by default. To get old behavior users should add `sql:"on_delete:CASCADE"` tag on foreign key field. - -## v6 - - - `types.Result` is renamed to `orm.Result`. - - Added `OnQueryProcessed` event that can be used to log / report queries timing. Query logger is removed. - - `orm.URLValues` is renamed to `orm.URLFilters`. It no longer adds ORDER clause. - - `orm.Pager` is renamed to `orm.Pagination`. - - Support for net.IP and net.IPNet. - - Support for context.Context. - - Bulk/multi updates. - - Query.WhereGroup for enclosing conditions in paretheses. - -## v5 - - - All fields are nullable by default. `,null` tag is replaced with `,notnull`. - - `Result.Affected` renamed to `Result.RowsAffected`. - - Added `Result.RowsReturned`. - - `Create` renamed to `Insert`, `BeforeCreate` to `BeforeInsert`, `AfterCreate` to `AfterInsert`. - - Indexed placeholders support, e.g. `db.Exec("SELECT ?0 + ?0", 1)`. - - Named placeholders are evaluated when query is executed. - - Added Update and Delete hooks. - - Order reworked to quote column names. OrderExpr added to bypass Order quoting restrictions. - - Group reworked to quote column names. GroupExpr added to bypass Group quoting restrictions. - -## v4 - - - `Options.Host` and `Options.Port` merged into `Options.Addr`. - - Added `Options.MaxRetries`. Now queries are not retried by default. - - `LoadInto` renamed to `Scan`, `ColumnLoader` renamed to `ColumnScanner`, LoadColumn renamed to ScanColumn, `NewRecord() interface{}` changed to `NewModel() ColumnScanner`, `AppendQuery(dst []byte) []byte` changed to `AppendValue(dst []byte, quote bool) ([]byte, error)`. - - Structs, maps and slices are marshalled to JSON by default. - - Added support for scanning slices, .e.g. scanning `[]int`. - - Added object relational mapping. diff --git a/vendor/github.com/go-pg/pg/README.md b/vendor/github.com/go-pg/pg/README.md deleted file mode 100644 index 8e652ff52..000000000 --- a/vendor/github.com/go-pg/pg/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# PostgreSQL client and ORM for Golang - -[![Build Status](https://travis-ci.org/go-pg/pg.svg?branch=master)](https://travis-ci.org/go-pg/pg) -[![GoDoc](https://godoc.org/github.com/go-pg/pg?status.svg)](https://godoc.org/github.com/go-pg/pg) - -## Features: - -- Basic types: integers, floats, string, bool, time.Time, net.IP, net.IPNet. -- sql.NullBool, sql.NullString, sql.NullInt64, sql.NullFloat64 and [pg.NullTime](http://godoc.org/github.com/go-pg/pg#NullTime). -- [sql.Scanner](http://golang.org/pkg/database/sql/#Scanner) and [sql/driver.Valuer](http://golang.org/pkg/database/sql/driver/#Valuer) interfaces. -- Structs, maps and arrays are marshalled as JSON by default. -- PostgreSQL multidimensional Arrays using [array tag](https://godoc.org/github.com/go-pg/pg#example-DB-Model-PostgresArrayStructTag) and [Array wrapper](https://godoc.org/github.com/go-pg/pg#example-Array). -- Hstore using [hstore tag](https://godoc.org/github.com/go-pg/pg#example-DB-Model-HstoreStructTag) and [Hstore wrapper](https://godoc.org/github.com/go-pg/pg#example-Hstore). -- [Composite types](https://godoc.org/github.com/go-pg/pg#example-DB-Model-CompositeType). -- All struct fields are nullable by default and zero values (empty string, 0, zero time, empty map or slice) are marshalled as SQL `NULL`. `sql:",notnull"` tag is used to reverse this behaviour. -- [Transactions](http://godoc.org/github.com/go-pg/pg#example-DB-Begin). -- [Prepared statements](http://godoc.org/github.com/go-pg/pg#example-DB-Prepare). -- [Notifications](http://godoc.org/github.com/go-pg/pg#example-Listener) using `LISTEN` and `NOTIFY`. -- [Copying data](http://godoc.org/github.com/go-pg/pg#example-DB-CopyFrom) using `COPY FROM` and `COPY TO`. -- [Timeouts](http://godoc.org/github.com/go-pg/pg#Options). -- Automatic connection pooling with [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support. -- Queries retries on network errors. -- Working with models using [ORM](https://godoc.org/github.com/go-pg/pg#example-DB-Model) and [SQL](https://godoc.org/github.com/go-pg/pg#example-DB-Query). -- Scanning variables using [ORM](https://godoc.org/github.com/go-pg/pg#example-DB-Select-SomeColumnsIntoVars) and [SQL](https://godoc.org/github.com/go-pg/pg#example-Scan). -- [SelectOrInsert](https://godoc.org/github.com/go-pg/pg#example-DB-Insert-SelectOrInsert) using on-conflict. -- [INSERT ... ON CONFLICT DO UPDATE](https://godoc.org/github.com/go-pg/pg#example-DB-Insert-OnConflictDoUpdate) using ORM. -- Bulk/batch [inserts](https://godoc.org/github.com/go-pg/pg#example-DB-Insert-BulkInsert), [updates](https://godoc.org/github.com/go-pg/pg#example-DB-Update-BulkUpdate), and [deletes](https://godoc.org/github.com/go-pg/pg#example-DB-Delete-BulkDelete). -- Common table expressions using [WITH](https://godoc.org/github.com/go-pg/pg#example-DB-Select-With) and [WrapWith](https://godoc.org/github.com/go-pg/pg#example-DB-Select-WrapWith). -- [CountEstimate](https://godoc.org/github.com/go-pg/pg#example-DB-Model-CountEstimate) using `EXPLAIN` to get [estimated number of matching rows](https://wiki.postgresql.org/wiki/Count_estimate). -- ORM supports [has one](https://godoc.org/github.com/go-pg/pg#example-DB-Model-HasOne), [belongs to](https://godoc.org/github.com/go-pg/pg#example-DB-Model-BelongsTo), [has many](https://godoc.org/github.com/go-pg/pg#example-DB-Model-HasMany), and [many to many](https://godoc.org/github.com/go-pg/pg#example-DB-Model-ManyToMany) with composite/multi-column primary keys. -- [Soft deletes](https://godoc.org/github.com/go-pg/pg#example-DB-Model-SoftDelete). -- [Creating tables from structs](https://godoc.org/github.com/go-pg/pg#example-DB-CreateTable). -- [Pagination](https://godoc.org/github.com/go-pg/pg/orm#Pagination) and [URL filters](https://godoc.org/github.com/go-pg/pg/orm#URLFilters) helpers. -- [ForEach](https://godoc.org/github.com/go-pg/pg#example-DB-Model-ForEach) that calls a function for each row returned by the query without loading all rows into the memory. -- Works with PgBouncer in transaction pooling mode. -- [Migrations](https://github.com/go-pg/migrations). -- [Sharding](https://github.com/go-pg/sharding). - -## Get Started - -```shell -go get -u github.com/go-pg/pg -``` - -- [Wiki](https://github.com/go-pg/pg/wiki) -- [API docs](http://godoc.org/github.com/go-pg/pg) -- [Examples](http://godoc.org/github.com/go-pg/pg#pkg-examples) - -## Look & Feel - -```go -package pg_test - -import ( - "fmt" - - "github.com/go-pg/pg" - "github.com/go-pg/pg/orm" -) - -type User struct { - Id int64 - Name string - Emails []string -} - -func (u User) String() string { - return fmt.Sprintf("User<%d %s %v>", u.Id, u.Name, u.Emails) -} - -type Story struct { - Id int64 - Title string - AuthorId int64 - Author *User -} - -func (s Story) String() string { - return fmt.Sprintf("Story<%d %s %s>", s.Id, s.Title, s.Author) -} - -func ExampleDB_Model() { - db := pg.Connect(&pg.Options{ - User: "postgres", - }) - defer db.Close() - - err := createSchema(db) - if err != nil { - panic(err) - } - - user1 := &User{ - Name: "admin", - Emails: []string{"admin1@admin", "admin2@admin"}, - } - err = db.Insert(user1) - if err != nil { - panic(err) - } - - err = db.Insert(&User{ - Name: "root", - Emails: []string{"root1@root", "root2@root"}, - }) - if err != nil { - panic(err) - } - - story1 := &Story{ - Title: "Cool story", - AuthorId: user1.Id, - } - err = db.Insert(story1) - if err != nil { - panic(err) - } - - // Select user by primary key. - user := &User{Id: user1.Id} - err = db.Select(user) - if err != nil { - panic(err) - } - - // Select all users. - var users []User - err = db.Model(&users).Select() - if err != nil { - panic(err) - } - - // Select story and associated author in one query. - story := new(Story) - err = db.Model(story). - Relation("Author"). - Where("story.id = ?", story1.Id). - Select() - if err != nil { - panic(err) - } - - fmt.Println(user) - fmt.Println(users) - fmt.Println(story) - // Output: User<1 admin [admin1@admin admin2@admin]> - // [User<1 admin [admin1@admin admin2@admin]> User<2 root [root1@root root2@root]>] - // Story<1 Cool story User<1 admin [admin1@admin admin2@admin]>> -} - -func createSchema(db *pg.DB) error { - for _, model := range []interface{}{(*User)(nil), (*Story)(nil)} { - err := db.CreateTable(model, &orm.CreateTableOptions{ - Temp: true, - }) - if err != nil { - return err - } - } - return nil -} -``` - -## See also - -- [Golang msgpack](https://github.com/vmihailenco/msgpack) -- [Golang message task queue](https://github.com/go-msgqueue/msgqueue) diff --git a/vendor/github.com/go-pg/pg/db.go b/vendor/github.com/go-pg/pg/db.go deleted file mode 100644 index c8bbac06c..000000000 --- a/vendor/github.com/go-pg/pg/db.go +++ /dev/null @@ -1,517 +0,0 @@ -package pg - -import ( - "context" - "fmt" - "io" - "time" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/pool" - "github.com/go-pg/pg/orm" -) - -// Connect connects to a database using provided options. -// -// The returned DB is safe for concurrent use by multiple goroutines -// and maintains its own connection pool. -func Connect(opt *Options) *DB { - opt.init() - return &DB{ - opt: opt, - pool: newConnPool(opt), - } -} - -// DB is a database handle representing a pool of zero or more -// underlying connections. It's safe for concurrent use by multiple -// goroutines. -type DB struct { - opt *Options - pool pool.Pooler - fmter orm.Formatter - - queryProcessedHooks []queryProcessedHook - - ctx context.Context -} - -var _ orm.DB = (*DB)(nil) - -func (db *DB) String() string { - return fmt.Sprintf("DB", db.opt.Addr, db.fmter) -} - -// Options returns read-only Options that were used to connect to the DB. -func (db *DB) Options() *Options { - return db.opt -} - -// Context returns DB context. -func (db *DB) Context() context.Context { - if db.ctx != nil { - return db.ctx - } - return context.Background() -} - -// WithContext returns a copy of the DB that uses the ctx. -func (db *DB) WithContext(ctx context.Context) *DB { - return &DB{ - opt: db.opt, - pool: db.pool, - fmter: db.fmter, - - queryProcessedHooks: copyQueryProcessedHooks(db.queryProcessedHooks), - - ctx: ctx, - } -} - -// WithTimeout returns a copy of the DB that uses d as the read/write timeout. -func (db *DB) WithTimeout(d time.Duration) *DB { - newopt := *db.opt - newopt.ReadTimeout = d - newopt.WriteTimeout = d - - return &DB{ - opt: &newopt, - pool: db.pool, - fmter: db.fmter, - - queryProcessedHooks: copyQueryProcessedHooks(db.queryProcessedHooks), - - ctx: db.ctx, - } -} - -// WithParam returns a copy of the DB that replaces the param with the value -// in queries. -func (db *DB) WithParam(param string, value interface{}) *DB { - return &DB{ - opt: db.opt, - pool: db.pool, - fmter: db.fmter.WithParam(param, value), - - queryProcessedHooks: copyQueryProcessedHooks(db.queryProcessedHooks), - - ctx: db.ctx, - } -} - -// Param returns value for the param. -func (db *DB) Param(param string) interface{} { - return db.fmter.Param(param) -} - -type PoolStats pool.Stats - -// PoolStats returns connection pool stats. -func (db *DB) PoolStats() *PoolStats { - stats := db.pool.Stats() - return (*PoolStats)(stats) -} - -func (db *DB) retryBackoff(retry int) time.Duration { - return internal.RetryBackoff(retry, db.opt.MinRetryBackoff, db.opt.MaxRetryBackoff) -} - -func (db *DB) conn() (*pool.Conn, error) { - cn, err := db.pool.Get() - if err != nil { - return nil, err - } - - if cn.InitedAt.IsZero() { - cn.InitedAt = time.Now() - err = db.initConn(cn) - if err != nil { - db.pool.Remove(cn) - return nil, err - } - } - - return cn, nil -} - -func (db *DB) initConn(cn *pool.Conn) error { - if db.opt.TLSConfig != nil { - err := db.enableSSL(cn, db.opt.TLSConfig) - if err != nil { - return err - } - } - - err := db.startup(cn, db.opt.User, db.opt.Password, db.opt.Database, db.opt.ApplicationName) - if err != nil { - return err - } - - if db.opt.OnConnect != nil { - dbConn := &DB{ - opt: db.opt, - pool: pool.NewSingleConnPool(cn), - fmter: db.fmter, - } - return db.opt.OnConnect(dbConn) - } - - return nil -} - -func (db *DB) freeConn(cn *pool.Conn, err error) { - if !isBadConn(err, false) { - db.pool.Put(cn) - } else { - db.pool.Remove(cn) - } -} - -func (db *DB) shouldRetry(err error) bool { - if err == nil { - return false - } - if pgerr, ok := err.(Error); ok { - switch pgerr.Field('C') { - case "40001": // serialization_failure - return true - case "55000": // attempted to delete invisible tuple - return true - case "57014": // statement_timeout - return db.opt.RetryStatementTimeout - default: - return false - } - } - return isNetworkError(err) -} - -// Close closes the database client, releasing any open resources. -// -// It is rare to Close a DB, as the DB handle is meant to be -// long-lived and shared between many goroutines. -func (db *DB) Close() error { - return db.pool.Close() -} - -// Exec executes a query ignoring returned rows. The params are for any -// placeholders in the query. -func (db *DB) Exec(query interface{}, params ...interface{}) (res orm.Result, err error) { - for attempt := 0; attempt <= db.opt.MaxRetries; attempt++ { - var cn *pool.Conn - - if attempt >= 1 { - time.Sleep(db.retryBackoff(attempt - 1)) - } - - cn, err = db.conn() - if err != nil { - continue - } - - start := time.Now() - res, err = db.simpleQuery(cn, query, params...) - db.freeConn(cn, err) - db.queryProcessed(db, start, query, params, attempt, res, err) - - if !db.shouldRetry(err) { - break - } - } - return res, err -} - -// ExecOne acts like Exec, but query must affect only one row. It -// returns ErrNoRows error when query returns zero rows or -// ErrMultiRows when query returns multiple rows. -func (db *DB) ExecOne(query interface{}, params ...interface{}) (orm.Result, error) { - res, err := db.Exec(query, params...) - if err != nil { - return nil, err - } - - if err := internal.AssertOneRow(res.RowsAffected()); err != nil { - return nil, err - } - return res, nil -} - -// Query executes a query that returns rows, typically a SELECT. -// The params are for any placeholders in the query. -func (db *DB) Query(model, query interface{}, params ...interface{}) (res orm.Result, err error) { - for attempt := 0; attempt <= db.opt.MaxRetries; attempt++ { - var cn *pool.Conn - - if attempt >= 1 { - time.Sleep(db.retryBackoff(attempt - 1)) - } - - cn, err = db.conn() - if err != nil { - continue - } - - start := time.Now() - res, err = db.simpleQueryData(cn, model, query, params...) - db.freeConn(cn, err) - db.queryProcessed(db, start, query, params, attempt, res, err) - - if !db.shouldRetry(err) { - break - } - } - if err != nil { - return nil, err - } - - if mod := res.Model(); mod != nil && res.RowsReturned() > 0 { - if err = mod.AfterQuery(db); err != nil { - return res, err - } - } - - return res, nil -} - -// QueryOne acts like Query, but query must return only one row. It -// returns ErrNoRows error when query returns zero rows or -// ErrMultiRows when query returns multiple rows. -func (db *DB) QueryOne(model, query interface{}, params ...interface{}) (orm.Result, error) { - res, err := db.Query(model, query, params...) - if err != nil { - return nil, err - } - - if err := internal.AssertOneRow(res.RowsAffected()); err != nil { - return nil, err - } - return res, nil -} - -// Listen listens for notifications sent with NOTIFY command. -func (db *DB) Listen(channels ...string) *Listener { - ln := &Listener{ - db: db, - } - ln.init() - _ = ln.Listen(channels...) - return ln -} - -// CopyFrom copies data from reader to a table. -func (db *DB) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (orm.Result, error) { - cn, err := db.conn() - if err != nil { - return nil, err - } - - res, err := db.copyFrom(cn, r, query, params...) - db.freeConn(cn, err) - return res, err -} - -func (db *DB) copyFrom(cn *pool.Conn, r io.Reader, query interface{}, params ...interface{}) (orm.Result, error) { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeQueryMsg(wb, db, query, params...) - }) - if err != nil { - return nil, err - } - - err = cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { - return readCopyInResponse(rd) - }) - if err != nil { - return nil, err - } - - for { - err = cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeCopyData(wb, r) - }) - if err != nil { - if err == io.EOF { - break - } - return nil, err - } - } - - err = cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - writeCopyDone(wb) - return nil - }) - if err != nil { - return nil, err - } - - var res orm.Result - err = cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { - res, err = readReadyForQuery(rd) - return err - }) - if err != nil { - return nil, err - } - - return res, nil -} - -// CopyTo copies data from a table to writer. -func (db *DB) CopyTo(w io.Writer, query interface{}, params ...interface{}) (orm.Result, error) { - cn, err := db.conn() - if err != nil { - return nil, err - } - - res, err := db.copyTo(cn, w, query, params...) - if err != nil { - db.freeConn(cn, err) - return nil, err - } - - db.pool.Put(cn) - return res, nil -} - -func (db *DB) copyTo(cn *pool.Conn, w io.Writer, query interface{}, params ...interface{}) (orm.Result, error) { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeQueryMsg(wb, db, query, params...) - }) - if err != nil { - return nil, err - } - - var res orm.Result - err = cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { - err := readCopyOutResponse(rd) - if err != nil { - return err - } - - res, err = readCopyData(rd, w) - return err - }) - if err != nil { - return nil, err - } - - return res, nil -} - -// Model returns new query for the model. -func (db *DB) Model(model ...interface{}) *orm.Query { - return orm.NewQuery(db, model...) -} - -// Select selects the model by primary key. -func (db *DB) Select(model interface{}) error { - return orm.Select(db, model) -} - -// Insert inserts the model updating primary keys if they are empty. -func (db *DB) Insert(model ...interface{}) error { - return orm.Insert(db, model...) -} - -// Update updates the model by primary key. -func (db *DB) Update(model interface{}) error { - return orm.Update(db, model) -} - -// Delete deletes the model by primary key. -func (db *DB) Delete(model interface{}) error { - return orm.Delete(db, model) -} - -// Delete forces delete of the model with deleted_at column. -func (db *DB) ForceDelete(model interface{}) error { - return orm.ForceDelete(db, model) -} - -// CreateTable creates table for the model. It recognizes following field tags: -// - notnull - sets NOT NULL constraint. -// - unique - sets UNIQUE constraint. -// - default:value - sets default value. -func (db *DB) CreateTable(model interface{}, opt *orm.CreateTableOptions) error { - return orm.CreateTable(db, model, opt) -} - -// DropTable drops table for the model. -func (db *DB) DropTable(model interface{}, opt *orm.DropTableOptions) error { - return orm.DropTable(db, model, opt) -} - -func (db *DB) CreateComposite(model interface{}, opt *orm.CreateCompositeOptions) error { - return orm.CreateComposite(db, model, opt) -} - -func (db *DB) DropComposite(model interface{}, opt *orm.DropCompositeOptions) error { - return orm.DropComposite(db, model, opt) -} - -func (db *DB) FormatQuery(dst []byte, query string, params ...interface{}) []byte { - return db.fmter.Append(dst, query, params...) -} - -func (db *DB) cancelRequest(processId, secretKey int32) error { - cn, err := db.pool.NewConn() - if err != nil { - return err - } - - err = cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - writeCancelRequestMsg(wb, processId, secretKey) - return nil - }) - if err != nil { - return err - } - - cn.Close() - return nil -} - -func (db *DB) simpleQuery( - cn *pool.Conn, query interface{}, params ...interface{}, -) (orm.Result, error) { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeQueryMsg(wb, db, query, params...) - }) - if err != nil { - return nil, err - } - - var res orm.Result - err = cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { - res, err = readSimpleQuery(rd) - return err - }) - if err != nil { - return nil, err - } - - return res, nil -} - -func (db *DB) simpleQueryData( - cn *pool.Conn, model, query interface{}, params ...interface{}, -) (orm.Result, error) { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeQueryMsg(wb, db, query, params...) - }) - if err != nil { - return nil, err - } - - var res orm.Result - err = cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { - res, err = readSimpleQueryData(rd, model) - return err - }) - if err != nil { - return nil, err - } - - return res, nil -} diff --git a/vendor/github.com/go-pg/pg/doc.go b/vendor/github.com/go-pg/pg/doc.go deleted file mode 100644 index f1d8eb192..000000000 --- a/vendor/github.com/go-pg/pg/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package github.com/go-pg/pg implements a PostgreSQL client. -*/ -package pg diff --git a/vendor/github.com/go-pg/pg/hook.go b/vendor/github.com/go-pg/pg/hook.go deleted file mode 100644 index ff6723b3f..000000000 --- a/vendor/github.com/go-pg/pg/hook.go +++ /dev/null @@ -1,145 +0,0 @@ -package pg - -import ( - "fmt" - "runtime" - "strings" - "time" - - "github.com/go-pg/pg/orm" -) - -type dummyDB struct { - orm.DB -} - -var _ orm.DB = dummyDB{} - -func (dummyDB) FormatQuery(dst []byte, query string, params ...interface{}) []byte { - return append(dst, query...) -} - -type QueryProcessedEvent struct { - StartTime time.Time - Func string - File string - Line int - - DB orm.DB - Query interface{} - Params []interface{} - Attempt int - Result orm.Result - Error error -} - -func (ev *QueryProcessedEvent) UnformattedQuery() (string, error) { - b, err := queryString(ev.Query) - if err != nil { - return "", err - } - return string(b), nil -} - -func (ev *QueryProcessedEvent) FormattedQuery() (string, error) { - b, err := appendQuery(nil, ev.DB, ev.Query, ev.Params...) - if err != nil { - return "", err - } - return string(b), nil -} - -func queryString(query interface{}) ([]byte, error) { - switch query := query.(type) { - case orm.QueryAppender: - query = query.Copy() - query.Query().DB(dummyDB{}) - return query.AppendQuery(nil) - case string: - return dummyDB{}.FormatQuery(nil, query), nil - default: - return nil, fmt.Errorf("pg: can't append %T", query) - } -} - -type queryProcessedHook func(*QueryProcessedEvent) - -// OnQueryProcessed calls the fn with QueryProcessedEvent -// when query is processed. -func (db *DB) OnQueryProcessed(fn func(*QueryProcessedEvent)) { - db.queryProcessedHooks = append(db.queryProcessedHooks, fn) -} - -func (db *DB) queryProcessed( - ormDB orm.DB, - start time.Time, - query interface{}, - params []interface{}, - attempt int, - res orm.Result, - err error, -) { - if len(db.queryProcessedHooks) == 0 { - return - } - - funcName, file, line := fileLine(2) - event := &QueryProcessedEvent{ - StartTime: start, - Func: funcName, - File: file, - Line: line, - - DB: ormDB, - Query: query, - Params: params, - Attempt: attempt, - Result: res, - Error: err, - } - for _, hook := range db.queryProcessedHooks { - hook(event) - } -} - -const packageName = "github.com/go-pg/pg" - -func fileLine(depth int) (string, string, int) { - for i := depth; ; i++ { - pc, file, line, ok := runtime.Caller(i) - if !ok { - break - } - if strings.Contains(file, packageName) { - continue - } - _, funcName := packageFuncName(pc) - return funcName, file, line - } - return "", "", 0 -} - -func packageFuncName(pc uintptr) (string, string) { - f := runtime.FuncForPC(pc) - if f == nil { - return "", "" - } - - packageName := "" - funcName := f.Name() - - if ind := strings.LastIndex(funcName, "/"); ind > 0 { - packageName += funcName[:ind+1] - funcName = funcName[ind+1:] - } - if ind := strings.Index(funcName, "."); ind > 0 { - packageName += funcName[:ind] - funcName = funcName[ind+1:] - } - - return packageName, funcName -} - -func copyQueryProcessedHooks(s []queryProcessedHook) []queryProcessedHook { - return s[:len(s):len(s)] -} diff --git a/vendor/github.com/go-pg/pg/internal/internal.go b/vendor/github.com/go-pg/pg/internal/internal.go deleted file mode 100644 index ad3fc3c9f..000000000 --- a/vendor/github.com/go-pg/pg/internal/internal.go +++ /dev/null @@ -1,24 +0,0 @@ -package internal - -import ( - "math/rand" - "time" -) - -// Retry backoff with jitter sleep to prevent overloaded conditions during intervals -// https://www.awsarchitectureblog.com/2015/03/backoff.html -func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration { - if retry < 0 { - retry = 0 - } - - backoff := minBackoff << uint(retry) - if backoff > maxBackoff || backoff < minBackoff { - backoff = maxBackoff - } - - if backoff == 0 { - return 0 - } - return time.Duration(rand.Int63n(int64(backoff))) -} diff --git a/vendor/github.com/go-pg/pg/internal/log.go b/vendor/github.com/go-pg/pg/internal/log.go deleted file mode 100644 index fd14222ee..000000000 --- a/vendor/github.com/go-pg/pg/internal/log.go +++ /dev/null @@ -1,15 +0,0 @@ -package internal - -import ( - "fmt" - "log" -) - -var Logger *log.Logger - -func Logf(s string, args ...interface{}) { - if Logger == nil { - return - } - Logger.Output(2, fmt.Sprintf(s, args...)) -} diff --git a/vendor/github.com/go-pg/pg/internal/parser/array_parser.go b/vendor/github.com/go-pg/pg/internal/parser/array_parser.go deleted file mode 100644 index 524d1244d..000000000 --- a/vendor/github.com/go-pg/pg/internal/parser/array_parser.go +++ /dev/null @@ -1,92 +0,0 @@ -package parser - -import ( - "bytes" - "fmt" -) - -type ArrayParser struct { - *Parser - - stickyErr error -} - -func NewArrayParser(b []byte) *ArrayParser { - var err error - if len(b) < 2 || b[0] != '{' || b[len(b)-1] != '}' { - err = fmt.Errorf("pg: can't parse array: %s", string(b)) - } else { - b = b[1 : len(b)-1] - } - return &ArrayParser{ - Parser: New(b), - - stickyErr: err, - } -} - -func (p *ArrayParser) NextElem() ([]byte, error) { - if p.stickyErr != nil { - return nil, p.stickyErr - } - - switch c := p.Peek(); c { - case '"': - p.Advance() - b := p.readSubstring() - - if p.Valid() { - if err := p.MustSkip(','); err != nil { - return nil, err - } - } - - return b, nil - case '{': - b := p.readSubArray() - if b != nil { - b = append(b, '}') - } - - if p.Valid() { - if err := p.MustSkip(','); err != nil { - return nil, err - } - } - - return b, nil - default: - b, _ := p.ReadSep(',') - if bytes.Equal(b, pgNull) { - b = nil - } - return b, nil - } -} - -func (p *ArrayParser) readSubArray() []byte { - var b []byte - for p.Valid() { - c := p.Read() - switch c { - case '"': - b = append(b, '"') - for { - bb, ok := p.ReadSep('"') - b = append(b, bb...) - stop := len(b) > 0 && b[len(b)-1] != '\\' - if ok { - b = append(b, '"') - } - if stop { - break - } - } - case '}': - return b - default: - b = append(b, c) - } - } - return b -} diff --git a/vendor/github.com/go-pg/pg/internal/parser/composite_parser.go b/vendor/github.com/go-pg/pg/internal/parser/composite_parser.go deleted file mode 100644 index 2b918eaa9..000000000 --- a/vendor/github.com/go-pg/pg/internal/parser/composite_parser.go +++ /dev/null @@ -1,53 +0,0 @@ -package parser - -import ( - "fmt" -) - -type CompositeParser struct { - *Parser - - stickyErr error -} - -func NewCompositeParser(b []byte) *CompositeParser { - var err error - if len(b) < 2 || b[0] != '(' || b[len(b)-1] != ')' { - err = fmt.Errorf("pg: can't parse composite value: %s", string(b)) - } else { - b = b[1 : len(b)-1] - } - return &CompositeParser{ - Parser: New(b), - - stickyErr: err, - } -} - -func (p *CompositeParser) NextElem() ([]byte, error) { - if p.stickyErr != nil { - return nil, p.stickyErr - } - - switch c := p.Peek(); c { - case '"': - b, err := p.ReadString() - if err != nil { - return nil, err - } - - if p.Valid() { - if err := p.MustSkip(','); err != nil { - return nil, err - } - } - - return b, nil - default: - b, _ := p.ReadSep(',') - if len(b) == 0 { // NULL - b = nil - } - return b, nil - } -} diff --git a/vendor/github.com/go-pg/pg/internal/parser/hstore_parser.go b/vendor/github.com/go-pg/pg/internal/parser/hstore_parser.go deleted file mode 100644 index f51561bd5..000000000 --- a/vendor/github.com/go-pg/pg/internal/parser/hstore_parser.go +++ /dev/null @@ -1,40 +0,0 @@ -package parser - -import "fmt" - -type HstoreParser struct { - *Parser -} - -func NewHstoreParser(b []byte) *HstoreParser { - return &HstoreParser{ - Parser: New(b), - } -} - -func (p *HstoreParser) NextKey() ([]byte, error) { - if p.Skip(',') { - p.Skip(' ') - } - - if !p.Skip('"') { - return nil, fmt.Errorf("pg: can't parse hstore key: %q", p.Bytes()) - } - - key := p.readSubstring() - if !(p.Skip('=') && p.Skip('>')) { - return nil, fmt.Errorf("pg: can't parse hstore key: %q", p.Bytes()) - } - - return key, nil -} - -func (p *HstoreParser) NextValue() ([]byte, error) { - if !p.Skip('"') { - return nil, fmt.Errorf("pg: can't parse hstore value: %q", p.Bytes()) - } - - value := p.readSubstring() - p.SkipBytes([]byte(", ")) - return value, nil -} diff --git a/vendor/github.com/go-pg/pg/internal/parser/parser.go b/vendor/github.com/go-pg/pg/internal/parser/parser.go deleted file mode 100644 index d94b7be26..000000000 --- a/vendor/github.com/go-pg/pg/internal/parser/parser.go +++ /dev/null @@ -1,170 +0,0 @@ -package parser - -import ( - "bytes" - "fmt" - "strconv" - - "github.com/go-pg/pg/internal" -) - -type Parser struct { - b []byte -} - -func New(b []byte) *Parser { - return &Parser{ - b: b, - } -} - -func NewString(s string) *Parser { - return New(internal.StringToBytes(s)) -} - -func (p *Parser) Bytes() []byte { - return p.b -} - -func (p *Parser) Valid() bool { - return len(p.b) > 0 -} - -func (p *Parser) Read() byte { - if p.Valid() { - c := p.b[0] - p.Advance() - return c - } - return 0 -} - -func (p *Parser) Peek() byte { - if p.Valid() { - return p.b[0] - } - return 0 -} - -func (p *Parser) Advance() { - p.b = p.b[1:] -} - -func (p *Parser) Skip(c byte) bool { - if p.Peek() == c { - p.Advance() - return true - } - return false -} - -func (p *Parser) MustSkip(c byte) error { - if p.Skip(c) { - return nil - } - return fmt.Errorf("expecting '%c', got %q", c, p.Bytes()) -} - -func (p *Parser) SkipBytes(b []byte) bool { - if len(b) > len(p.b) { - return false - } - if !bytes.Equal(p.b[:len(b)], b) { - return false - } - p.b = p.b[len(b):] - return true -} - -func (p *Parser) ReadSep(c byte) ([]byte, bool) { - ind := bytes.IndexByte(p.b, c) - if ind == -1 { - b := p.b - p.b = p.b[len(p.b):] - return b, false - } - - b := p.b[:ind] - p.b = p.b[ind+1:] - return b, true -} - -func (p *Parser) ReadIdentifier() (s string, numeric bool) { - end := len(p.b) - numeric = true - for i, ch := range p.b { - if isNum(ch) { - continue - } - if isAlpha(ch) || (i > 0 && ch == '_') { - numeric = false - continue - } - end = i - break - } - if end == 0 { - return "", false - } - b := p.b[:end] - p.b = p.b[end:] - return internal.BytesToString(b), numeric -} - -func (p *Parser) ReadNumber() int { - end := len(p.b) - for i, ch := range p.b { - if !isNum(ch) { - end = i - break - } - } - if end <= 0 { - return 0 - } - n, _ := strconv.Atoi(string(p.b[:end])) - p.b = p.b[end:] - return n -} - -func (p *Parser) ReadString() ([]byte, error) { - quote := p.Read() - b, ok := p.ReadSep(quote) - if !ok { - return nil, fmt.Errorf("can't find closing quote") - } - return b, nil -} - -func (p *Parser) readSubstring() []byte { - var b []byte - for p.Valid() { - c := p.Read() - switch c { - case '\\': - switch p.Peek() { - case '\\': - b = append(b, '\\') - p.Advance() - case '"': - b = append(b, '"') - p.Advance() - default: - b = append(b, c) - } - case '\'': - switch p.Peek() { - case '\'': - b = append(b, '\'') - p.Advance() - default: - b = append(b, c) - } - case '"': - return b - default: - b = append(b, c) - } - } - return b -} diff --git a/vendor/github.com/go-pg/pg/internal/parser/util.go b/vendor/github.com/go-pg/pg/internal/parser/util.go deleted file mode 100644 index 23844e31a..000000000 --- a/vendor/github.com/go-pg/pg/internal/parser/util.go +++ /dev/null @@ -1,15 +0,0 @@ -package parser - -var pgNull = []byte("NULL") - -func isNum(c byte) bool { - return c >= '0' && c <= '9' -} - -func isAlpha(c byte) bool { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') -} - -func isAlnum(c byte) bool { - return isAlpha(c) || isNum(c) -} diff --git a/vendor/github.com/go-pg/pg/internal/pool/conn.go b/vendor/github.com/go-pg/pg/internal/pool/conn.go deleted file mode 100644 index b1900eeca..000000000 --- a/vendor/github.com/go-pg/pg/internal/pool/conn.go +++ /dev/null @@ -1,129 +0,0 @@ -package pool - -import ( - "net" - "strconv" - "sync/atomic" - "time" -) - -var noDeadline = time.Time{} - -type Conn struct { - netConn net.Conn - - buf []byte - rd *Reader - rdLocked bool - wb *WriteBuffer - - InitedAt time.Time - pooled bool - usedAt atomic.Value - - ProcessId int32 - SecretKey int32 - - _lastId int64 -} - -func NewConn(netConn net.Conn) *Conn { - cn := &Conn{ - buf: makeBuffer(), - rd: NewReader(NewElasticBufReader(netConn)), - wb: NewWriteBuffer(), - } - cn.SetNetConn(netConn) - cn.SetUsedAt(time.Now()) - return cn -} - -func (cn *Conn) UsedAt() time.Time { - return cn.usedAt.Load().(time.Time) -} - -func (cn *Conn) SetUsedAt(tm time.Time) { - cn.usedAt.Store(tm) -} - -func (cn *Conn) RemoteAddr() net.Addr { - return cn.netConn.RemoteAddr() -} - -func (cn *Conn) SetNetConn(netConn net.Conn) { - cn.netConn = netConn - cn.rd.Reset(netConn) -} - -func (cn *Conn) NetConn() net.Conn { - return cn.netConn -} - -func (cn *Conn) NextId() string { - cn._lastId++ - return strconv.FormatInt(cn._lastId, 10) -} - -func (cn *Conn) setReadTimeout(timeout time.Duration) error { - now := time.Now() - cn.SetUsedAt(now) - if timeout > 0 { - return cn.netConn.SetReadDeadline(now.Add(timeout)) - } - return cn.netConn.SetReadDeadline(noDeadline) -} - -func (cn *Conn) setWriteTimeout(timeout time.Duration) error { - now := time.Now() - cn.SetUsedAt(now) - if timeout > 0 { - return cn.netConn.SetWriteDeadline(now.Add(timeout)) - } - return cn.netConn.SetWriteDeadline(noDeadline) -} - -func (cn *Conn) LockReaderBuffer() { - cn.rdLocked = true - cn.rd.ResetBuffer(makeBuffer()) -} - -func (cn *Conn) WithReader(timeout time.Duration, fn func(rd *Reader) error) error { - _ = cn.setReadTimeout(timeout) - - if !cn.rdLocked { - cn.rd.ResetBuffer(cn.buf) - } - - err := fn(cn.rd) - - if !cn.rdLocked { - cn.buf = cn.rd.Buffer() - } - - return err -} - -func (cn *Conn) WithWriter(timeout time.Duration, fn func(wb *WriteBuffer) error) error { - _ = cn.setWriteTimeout(timeout) - - cn.wb.ResetBuffer(cn.buf) - - firstErr := fn(cn.wb) - - _, err := cn.netConn.Write(cn.wb.Bytes) - cn.buf = cn.wb.Buffer() - if err != nil && firstErr == nil { - firstErr = err - } - - return firstErr -} - -func (cn *Conn) Close() error { - return cn.netConn.Close() -} - -func makeBuffer() []byte { - const defaulBufSize = 4096 - return make([]byte, defaulBufSize) -} diff --git a/vendor/github.com/go-pg/pg/internal/pool/elastic_reader.go b/vendor/github.com/go-pg/pg/internal/pool/elastic_reader.go deleted file mode 100644 index b4f8a6eef..000000000 --- a/vendor/github.com/go-pg/pg/internal/pool/elastic_reader.go +++ /dev/null @@ -1,185 +0,0 @@ -package pool - -import ( - "bytes" - "errors" - "io" -) - -const defaultBufSize = 4096 - -// ElasticBufReader is like bufio.Reader but instead of returning ErrBufferFull -// it automatically grows the buffer. -type ElasticBufReader struct { - buf []byte - rd io.Reader // reader provided by the client - r, w int // buf read and write positions - err error -} - -func NewElasticBufReader(rd io.Reader) *ElasticBufReader { - return &ElasticBufReader{ - rd: rd, - } -} - -func (b *ElasticBufReader) Reset(rd io.Reader) { - b.rd = rd - b.r, b.w = 0, 0 - b.err = nil -} - -func (b *ElasticBufReader) Buffer() []byte { - return b.buf -} - -func (b *ElasticBufReader) ResetBuffer(buf []byte) { - b.buf = buf - b.r, b.w = 0, 0 - b.err = nil -} - -// Buffered returns the number of bytes that can be read from the current buffer. -func (b *ElasticBufReader) Buffered() int { - return b.w - b.r -} - -func (b *ElasticBufReader) Bytes() []byte { - return b.buf[b.r:b.w] -} - -var errNegativeRead = errors.New("bufio: reader returned negative count from Read") - -// fill reads a new chunk into the buffer. -func (b *ElasticBufReader) fill() { - // Slide existing data to beginning. - if b.r > 0 { - copy(b.buf, b.buf[b.r:b.w]) - b.w -= b.r - b.r = 0 - } - - if b.w >= len(b.buf) { - panic("bufio: tried to fill full buffer") - } - - // Read new data: try a limited number of times. - const maxConsecutiveEmptyReads = 100 - for i := maxConsecutiveEmptyReads; i > 0; i-- { - n, err := b.rd.Read(b.buf[b.w:]) - if n < 0 { - panic(errNegativeRead) - } - b.w += n - if err != nil { - b.err = err - return - } - if n > 0 { - return - } - } - b.err = io.ErrNoProgress -} - -func (b *ElasticBufReader) readErr() error { - err := b.err - b.err = nil - return err -} - -func (b *ElasticBufReader) ReadSlice(delim byte) (line []byte, err error) { - for { - // Search buffer. - if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 { - line = b.buf[b.r : b.r+i+1] - b.r += i + 1 - break - } - - // Pending error? - if b.err != nil { - line = b.buf[b.r:b.w] - b.r = b.w - err = b.readErr() - break - } - - // Buffer full? - if b.Buffered() >= len(b.buf) { - b.grow(len(b.buf) + defaultBufSize) - } - - b.fill() // buffer is not full - } - - return -} - -func (b *ElasticBufReader) ReadLine() (line []byte, err error) { - line, err = b.ReadSlice('\n') - if len(line) == 0 { - if err != nil { - line = nil - } - return - } - err = nil - - if line[len(line)-1] == '\n' { - drop := 1 - if len(line) > 1 && line[len(line)-2] == '\r' { - drop = 2 - } - line = line[:len(line)-drop] - } - return -} - -func (b *ElasticBufReader) ReadByte() (byte, error) { - for b.r == b.w { - if b.err != nil { - return 0, b.readErr() - } - b.fill() // buffer is empty - } - c := b.buf[b.r] - b.r++ - return c, nil -} - -func (b *ElasticBufReader) ReadN(n int) ([]byte, error) { - b.grow(n) - for b.Buffered() < n { - // Pending error? - if b.err != nil { - buf := b.buf[b.r:b.w] - b.r = b.w - return buf, b.readErr() - } - - b.fill() - } - - buf := b.buf[b.r : b.r+n] - b.r += n - return buf, nil -} - -func (b *ElasticBufReader) grow(n int) { - if b.w-b.r >= n { - return - } - - // Slide existing data to beginning. - if b.r > 0 { - copy(b.buf, b.buf[b.r:b.w]) - b.w -= b.r - b.r = 0 - } - - // Extend buffer if needed. - if d := n - len(b.buf); d > 0 { - b.buf = append(b.buf, make([]byte, d)...) - } -} diff --git a/vendor/github.com/go-pg/pg/internal/pool/pool_single.go b/vendor/github.com/go-pg/pg/internal/pool/pool_single.go deleted file mode 100644 index b35b78afb..000000000 --- a/vendor/github.com/go-pg/pg/internal/pool/pool_single.go +++ /dev/null @@ -1,53 +0,0 @@ -package pool - -type SingleConnPool struct { - cn *Conn -} - -var _ Pooler = (*SingleConnPool)(nil) - -func NewSingleConnPool(cn *Conn) *SingleConnPool { - return &SingleConnPool{ - cn: cn, - } -} - -func (p *SingleConnPool) NewConn() (*Conn, error) { - panic("not implemented") -} - -func (p *SingleConnPool) CloseConn(*Conn) error { - panic("not implemented") -} - -func (p *SingleConnPool) Get() (*Conn, error) { - return p.cn, nil -} - -func (p *SingleConnPool) Put(cn *Conn) { - if p.cn != cn { - panic("p.cn != cn") - } -} - -func (p *SingleConnPool) Remove(cn *Conn) { - if p.cn != cn { - panic("p.cn != cn") - } -} - -func (p *SingleConnPool) Len() int { - return 1 -} - -func (p *SingleConnPool) IdleLen() int { - return 0 -} - -func (p *SingleConnPool) Stats() *Stats { - return nil -} - -func (p *SingleConnPool) Close() error { - return nil -} diff --git a/vendor/github.com/go-pg/pg/internal/pool/reader.go b/vendor/github.com/go-pg/pg/internal/pool/reader.go deleted file mode 100644 index 9eedd4762..000000000 --- a/vendor/github.com/go-pg/pg/internal/pool/reader.go +++ /dev/null @@ -1,71 +0,0 @@ -package pool - -import ( - "encoding/binary" - - "github.com/go-pg/pg/internal" -) - -type Reader struct { - *ElasticBufReader - Columns [][]byte -} - -func NewReader(buf *ElasticBufReader) *Reader { - return &Reader{ElasticBufReader: buf} -} - -func (rd *Reader) ReadInt16() (int16, error) { - b, err := rd.ReadN(2) - if err != nil { - return 0, err - } - return int16(binary.BigEndian.Uint16(b)), nil -} - -func (rd *Reader) ReadInt32() (int32, error) { - b, err := rd.ReadN(4) - if err != nil { - return 0, err - } - return int32(binary.BigEndian.Uint32(b)), nil -} - -func (rd *Reader) ReadString() (string, error) { - b, err := rd.ReadSlice(0) - if err != nil { - return "", err - } - return string(b[:len(b)-1]), nil -} - -func (rd *Reader) ReadError() (error, error) { - m := make(map[byte]string) - for { - c, err := rd.ReadByte() - if err != nil { - return nil, err - } - if c == 0 { - break - } - s, err := rd.ReadString() - if err != nil { - return nil, err - } - m[c] = s - } - return internal.NewPGError(m), nil -} - -func (rd *Reader) ReadMessageType() (byte, int, error) { - c, err := rd.ReadByte() - if err != nil { - return 0, 0, err - } - l, err := rd.ReadInt32() - if err != nil { - return 0, 0, err - } - return c, int(l) - 4, nil -} diff --git a/vendor/github.com/go-pg/pg/listener.go b/vendor/github.com/go-pg/pg/listener.go deleted file mode 100644 index 2eade2b45..000000000 --- a/vendor/github.com/go-pg/pg/listener.go +++ /dev/null @@ -1,316 +0,0 @@ -package pg - -import ( - "errors" - "sync" - "time" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/pool" - "github.com/go-pg/pg/types" -) - -const gopgChannel = "gopg:ping" - -var errListenerClosed = errors.New("pg: listener is closed") - -// A notification received with LISTEN command. -type Notification struct { - Channel string - Payload string -} - -// Listener listens for notifications sent with NOTIFY command. -// It's NOT safe for concurrent use by multiple goroutines -// except the Channel API. -type Listener struct { - db *DB - - channels []string - - mu sync.Mutex - cn *pool.Conn - closed bool - exit chan struct{} - - chOnce sync.Once - ch chan *Notification - pingCh chan struct{} -} - -func (ln *Listener) init() { - ln.exit = make(chan struct{}) -} - -func (ln *Listener) conn() (*pool.Conn, error) { - ln.mu.Lock() - cn, err := ln._conn() - ln.mu.Unlock() - - switch err { - case nil: - return cn, nil - case errListenerClosed: - return nil, err - case pool.ErrClosed: - _ = ln.Close() - return nil, errListenerClosed - default: - internal.Logf("pg: Listen failed: %s", err) - return nil, err - } -} - -func (ln *Listener) _conn() (*pool.Conn, error) { - if ln.closed { - return nil, errListenerClosed - } - - if ln.cn != nil { - return ln.cn, nil - } - - cn, err := ln.db.pool.NewConn() - if err != nil { - return nil, err - } - cn.LockReaderBuffer() - - if cn.InitedAt.IsZero() { - err := ln.db.initConn(cn) - if err != nil { - _ = ln.db.pool.CloseConn(cn) - return nil, err - } - cn.InitedAt = time.Now() - } - - if len(ln.channels) > 0 { - err := ln.listen(cn, ln.channels...) - if err != nil { - _ = ln.db.pool.CloseConn(cn) - return nil, err - } - } - - ln.cn = cn - return cn, nil -} - -func (ln *Listener) releaseConn(cn *pool.Conn, err error, allowTimeout bool) { - ln.mu.Lock() - if ln.cn == cn { - if isBadConn(err, allowTimeout) { - ln._reconnect(err) - } - } - ln.mu.Unlock() -} - -func (ln *Listener) _closeTheCn(reason error) error { - if ln.cn == nil { - return nil - } - if !ln.closed { - internal.Logf("pg: discarding bad listener connection: %s", reason) - } - - err := ln.db.pool.CloseConn(ln.cn) - ln.cn = nil - return err -} - -func (ln *Listener) _reconnect(reason error) { - _ = ln._closeTheCn(reason) - _, _ = ln._conn() -} - -// Close closes the listener, releasing any open resources. -func (ln *Listener) Close() error { - ln.mu.Lock() - defer ln.mu.Unlock() - - if ln.closed { - return errListenerClosed - } - ln.closed = true - close(ln.exit) - - return ln._closeTheCn(errListenerClosed) -} - -// Listen starts listening for notifications on channels. -func (ln *Listener) Listen(channels ...string) error { - cn, err := ln.conn() - if err != nil { - return err - } - - err = ln.listen(cn, channels...) - if err != nil { - ln.releaseConn(cn, err, false) - return err - } - - ln.channels = appendIfNotExists(ln.channels, channels...) - return nil -} - -func (ln *Listener) listen(cn *pool.Conn, channels ...string) error { - err := cn.WithWriter(ln.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - for _, channel := range channels { - err := writeQueryMsg(wb, ln.db, "LISTEN ?", pgChan(channel)) - if err != nil { - return err - } - } - return nil - }) - return err -} - -// Receive indefinitely waits for a notification. This is low-level API -// and in most cases Channel should be used instead. -func (ln *Listener) Receive() (channel string, payload string, err error) { - return ln.ReceiveTimeout(0) -} - -// ReceiveTimeout waits for a notification until timeout is reached. -// This is low-level API and in most cases Channel should be used instead. -func (ln *Listener) ReceiveTimeout(timeout time.Duration) (channel, payload string, err error) { - cn, err := ln.conn() - if err != nil { - return "", "", err - } - - err = cn.WithReader(timeout, func(rd *pool.Reader) error { - channel, payload, err = readNotification(rd) - return err - }) - if err != nil { - ln.releaseConn(cn, err, timeout > 0) - return "", "", err - } - - return channel, payload, nil -} - -// Channel returns a channel for concurrently receiving notifications. -// It periodically sends Ping messages to test connection health. -// -// The channel is closed with Listener. Receive* APIs can not be used -// after channel is created. -func (ln *Listener) Channel() <-chan *Notification { - ln.chOnce.Do(ln.initChannel) - return ln.ch -} - -func (ln *Listener) initChannel() { - _ = ln.Listen(gopgChannel) - - ln.ch = make(chan *Notification, 100) - ln.pingCh = make(chan struct{}, 10) - - go func() { - var errCount int - for { - channel, payload, err := ln.Receive() - if err != nil { - if err == errListenerClosed { - close(ln.ch) - return - } - if errCount > 0 { - time.Sleep(ln.db.retryBackoff(errCount)) - } - errCount++ - continue - } - errCount = 0 - - // Any message is as good as a ping. - select { - case ln.pingCh <- struct{}{}: - default: - } - - switch channel { - case gopgChannel: - // ignore - default: - ln.ch <- &Notification{channel, payload} - } - } - }() - - go func() { - const timeout = 5 * time.Second - - timer := time.NewTimer(timeout) - timer.Stop() - - healthy := true - var pingErr error - for { - timer.Reset(timeout) - select { - case <-ln.pingCh: - healthy = true - if !timer.Stop() { - <-timer.C - } - case <-timer.C: - pingErr = ln.ping() - if healthy { - healthy = false - } else { - ln.mu.Lock() - ln._reconnect(pingErr) - ln.mu.Unlock() - } - case <-ln.exit: - return - } - } - }() -} - -func (ln *Listener) ping() error { - _, err := ln.db.Exec("NOTIFY ?", pgChan(gopgChannel)) - return err -} - -func appendIfNotExists(ss []string, es ...string) []string { -loop: - for _, e := range es { - for _, s := range ss { - if s == e { - continue loop - } - } - ss = append(ss, e) - } - return ss -} - -type pgChan string - -var _ types.ValueAppender = pgChan("") - -func (ch pgChan) AppendValue(b []byte, quote int) []byte { - if quote == 0 { - return append(b, ch...) - } - - b = append(b, '"') - for _, c := range []byte(ch) { - if c == '"' { - b = append(b, '"', '"') - } else { - b = append(b, c) - } - } - b = append(b, '"') - - return b -} diff --git a/vendor/github.com/go-pg/pg/orm/composite.go b/vendor/github.com/go-pg/pg/orm/composite.go deleted file mode 100644 index 45a11ff17..000000000 --- a/vendor/github.com/go-pg/pg/orm/composite.go +++ /dev/null @@ -1,56 +0,0 @@ -package orm - -import ( - "fmt" - "reflect" - - "github.com/go-pg/pg/internal/parser" - "github.com/go-pg/pg/types" -) - -func compositeScanner(typ reflect.Type) types.ScannerFunc { - return func(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - - if b == nil { - if !v.IsNil() { - v.Set(reflect.Zero(v.Type())) - } - return nil - } - - table := GetTable(typ) - p := parser.NewCompositeParser(b) - for i := 0; p.Valid(); i++ { - elem, err := p.NextElem() - if err != nil { - return err - } - - field := table.Fields[i] - err = field.ScanValue(v, elem) - if err != nil { - return err - } - } - - return nil - } -} - -func compositeAppender(typ reflect.Type) types.AppenderFunc { - return func(b []byte, v reflect.Value, quote int) []byte { - table := GetTable(typ) - b = append(b, '(') - for i, f := range table.Fields { - if i > 0 { - b = append(b, ',') - } - b = f.AppendValue(b, v, quote) - } - b = append(b, ')') - return b - } -} diff --git a/vendor/github.com/go-pg/pg/orm/composite_create.go b/vendor/github.com/go-pg/pg/orm/composite_create.go deleted file mode 100644 index 2714efa0f..000000000 --- a/vendor/github.com/go-pg/pg/orm/composite_create.go +++ /dev/null @@ -1,68 +0,0 @@ -package orm - -import ( - "errors" - "strconv" -) - -type CreateCompositeOptions struct { - Varchar int // replaces PostgreSQL data type `text` with `varchar(n)` -} - -func CreateComposite(db DB, model interface{}, opt *CreateCompositeOptions) error { - q := NewQuery(db, model) - _, err := q.db.Exec(createCompositeQuery{ - q: q, - opt: opt, - }) - return err -} - -type createCompositeQuery struct { - q *Query - opt *CreateCompositeOptions -} - -func (q createCompositeQuery) Copy() QueryAppender { - return q -} - -func (q createCompositeQuery) Query() *Query { - return q.q -} - -func (q createCompositeQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - if q.q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - - table := q.q.model.Table() - - b = append(b, "CREATE TYPE "...) - b = append(b, q.q.model.Table().Alias...) - b = append(b, " AS ("...) - - for i, field := range table.Fields { - if i > 0 { - b = append(b, ", "...) - } - - b = append(b, field.Column...) - b = append(b, " "...) - if q.opt != nil && q.opt.Varchar > 0 && - field.SQLType == "text" && !field.HasFlag(customTypeFlag) { - b = append(b, "varchar("...) - b = strconv.AppendInt(b, int64(q.opt.Varchar), 10) - b = append(b, ")"...) - } else { - b = append(b, field.SQLType...) - } - } - - b = append(b, ")"...) - - return b, nil -} diff --git a/vendor/github.com/go-pg/pg/orm/composite_drop.go b/vendor/github.com/go-pg/pg/orm/composite_drop.go deleted file mode 100644 index f2198030a..000000000 --- a/vendor/github.com/go-pg/pg/orm/composite_drop.go +++ /dev/null @@ -1,50 +0,0 @@ -package orm - -import "errors" - -type DropCompositeOptions struct { - IfExists bool - Cascade bool -} - -func DropComposite(db DB, model interface{}, opt *DropCompositeOptions) error { - q := NewQuery(db, model) - _, err := q.db.Exec(dropCompositeQuery{ - q: q, - opt: opt, - }) - return err -} - -type dropCompositeQuery struct { - q *Query - opt *DropCompositeOptions -} - -func (q dropCompositeQuery) Copy() QueryAppender { - return q -} - -func (q dropCompositeQuery) Query() *Query { - return q.q -} - -func (q dropCompositeQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - if q.q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - - b = append(b, "DROP TYPE "...) - if q.opt != nil && q.opt.IfExists { - b = append(b, "IF EXISTS "...) - } - b = append(b, q.q.model.Table().Alias...) - if q.opt != nil && q.opt.Cascade { - b = append(b, " CASCADE"...) - } - - return b, nil -} diff --git a/vendor/github.com/go-pg/pg/orm/delete.go b/vendor/github.com/go-pg/pg/orm/delete.go deleted file mode 100644 index 5bd188899..000000000 --- a/vendor/github.com/go-pg/pg/orm/delete.go +++ /dev/null @@ -1,83 +0,0 @@ -package orm - -import ( - "github.com/go-pg/pg/internal" -) - -func Delete(db DB, model interface{}) error { - res, err := NewQuery(db, model).WherePK().Delete() - if err != nil { - return err - } - return internal.AssertOneRow(res.RowsAffected()) -} - -func ForceDelete(db DB, model interface{}) error { - res, err := NewQuery(db, model).WherePK().ForceDelete() - if err != nil { - return err - } - return internal.AssertOneRow(res.RowsAffected()) -} - -type deleteQuery struct { - q *Query -} - -var _ QueryAppender = (*deleteQuery)(nil) - -func (q deleteQuery) Copy() QueryAppender { - return deleteQuery{ - q: q.q.Copy(), - } -} - -func (q deleteQuery) Query() *Query { - return q.q -} - -func (q deleteQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - - var err error - - if len(q.q.with) > 0 { - b, err = q.q.appendWith(b) - if err != nil { - return nil, err - } - } - - b = append(b, "DELETE FROM "...) - b = q.q.appendFirstTableWithAlias(b) - - if q.q.hasMultiTables() { - b = append(b, " USING "...) - b = q.q.appendOtherTables(b) - } - - b = append(b, " WHERE "...) - value := q.q.model.Value() - if q.q.isSliceModel() { - table := q.q.model.Table() - b = appendColumnAndSliceValue(b, value, table.Alias, table.PKs) - - if q.q.hasWhere() { - b = append(b, " AND "...) - b = q.q.appendWhere(b) - } - } else { - b, err = q.q.mustAppendWhere(b) - if err != nil { - return nil, err - } - } - - if len(q.q.returning) > 0 { - b = q.q.appendReturning(b) - } - - return b, nil -} diff --git a/vendor/github.com/go-pg/pg/orm/field.go b/vendor/github.com/go-pg/pg/orm/field.go deleted file mode 100644 index fc954bbf6..000000000 --- a/vendor/github.com/go-pg/pg/orm/field.go +++ /dev/null @@ -1,108 +0,0 @@ -package orm - -import ( - "reflect" - - "github.com/go-pg/pg/types" -) - -const ( - PrimaryKeyFlag = uint8(1) << iota - ForeignKeyFlag - NotNullFlag - UniqueFlag - ArrayFlag - customTypeFlag -) - -type Field struct { - Field reflect.StructField - Type reflect.Type - - GoName string // struct field name, e.g. Id - SQLName string // SQL name, .e.g. id - Column types.Q // escaped SQL name, e.g. "id" - SQLType string - Index []int - Default types.Q - OnDelete string - - flags uint8 - - append types.AppenderFunc - scan types.ScannerFunc - - isZero func(reflect.Value) bool -} - -func indexEqual(ind1, ind2 []int) bool { - if len(ind1) != len(ind2) { - return false - } - for i, ind := range ind1 { - if ind != ind2[i] { - return false - } - } - return true -} - -func (f *Field) Copy() *Field { - cp := *f - cp.Index = cp.Index[:len(f.Index):len(f.Index)] - return &cp -} - -func (f *Field) SetFlag(flag uint8) { - f.flags |= flag -} - -func (f *Field) HasFlag(flag uint8) bool { - return f.flags&flag != 0 -} - -func (f *Field) Value(strct reflect.Value) reflect.Value { - return strct.FieldByIndex(f.Index) -} - -func (f *Field) IsZero(strct reflect.Value) bool { - return f.isZero(f.Value(strct)) -} - -func (f *Field) OmitZero() bool { - return !f.HasFlag(NotNullFlag) -} - -func (f *Field) AppendValue(b []byte, strct reflect.Value, quote int) []byte { - fv := f.Value(strct) - if !f.HasFlag(NotNullFlag) && f.isZero(fv) { - return types.AppendNull(b, quote) - } - return f.append(b, fv, quote) -} - -func (f *Field) ScanValue(strct reflect.Value, b []byte) error { - fv := fieldByIndex(strct, f.Index) - return f.scan(fv, b) -} - -type Method struct { - Index int - - flags int8 - - appender func([]byte, reflect.Value, int) []byte -} - -func (m *Method) Has(flag int8) bool { - return m.flags&flag != 0 -} - -func (m *Method) Value(strct reflect.Value) reflect.Value { - return strct.Method(m.Index).Call(nil)[0] -} - -func (m *Method) AppendValue(dst []byte, strct reflect.Value, quote int) []byte { - mv := m.Value(strct) - return m.appender(dst, mv, quote) -} diff --git a/vendor/github.com/go-pg/pg/orm/format.go b/vendor/github.com/go-pg/pg/orm/format.go deleted file mode 100644 index 9c5f9788e..000000000 --- a/vendor/github.com/go-pg/pg/orm/format.go +++ /dev/null @@ -1,286 +0,0 @@ -package orm - -import ( - "bytes" - "fmt" - "sort" - "strconv" - "strings" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/parser" - "github.com/go-pg/pg/types" -) - -var formatter Formatter - -type FormatAppender interface { - AppendFormat([]byte, QueryFormatter) []byte -} - -type sepFormatAppender interface { - FormatAppender - AppendSep([]byte) []byte -} - -//------------------------------------------------------------------------------ - -type queryParamsAppender struct { - query string - params []interface{} -} - -var _ FormatAppender = (*queryParamsAppender)(nil) -var _ types.ValueAppender = (*queryParamsAppender)(nil) - -func Q(query string, params ...interface{}) *queryParamsAppender { - return &queryParamsAppender{query, params} -} - -func (q *queryParamsAppender) AppendFormat(b []byte, f QueryFormatter) []byte { - return f.FormatQuery(b, q.query, q.params...) -} - -func (q *queryParamsAppender) AppendValue(b []byte, quote int) []byte { - return q.AppendFormat(b, formatter) -} - -func (q *queryParamsAppender) Value() types.Q { - b := q.AppendValue(nil, 1) - return types.Q(internal.BytesToString(b)) -} - -//------------------------------------------------------------------------------ - -type condGroupAppender struct { - sep string - cond []sepFormatAppender -} - -var _ FormatAppender = (*condAppender)(nil) -var _ sepFormatAppender = (*condAppender)(nil) - -func (q *condGroupAppender) AppendSep(b []byte) []byte { - return append(b, q.sep...) -} - -func (q *condGroupAppender) AppendFormat(b []byte, f QueryFormatter) []byte { - b = append(b, '(') - for i, app := range q.cond { - if i > 0 { - b = app.AppendSep(b) - } - b = app.AppendFormat(b, f) - } - b = append(b, ')') - return b -} - -//------------------------------------------------------------------------------ - -type condAppender struct { - sep string - cond string - params []interface{} -} - -var _ FormatAppender = (*condAppender)(nil) -var _ sepFormatAppender = (*condAppender)(nil) - -func (q *condAppender) AppendSep(b []byte) []byte { - return append(b, q.sep...) -} - -func (q *condAppender) AppendFormat(b []byte, f QueryFormatter) []byte { - b = append(b, '(') - b = f.FormatQuery(b, q.cond, q.params...) - b = append(b, ')') - return b -} - -//------------------------------------------------------------------------------ - -type fieldAppender struct { - field string -} - -var _ FormatAppender = (*fieldAppender)(nil) - -func (a fieldAppender) AppendFormat(b []byte, f QueryFormatter) []byte { - return types.AppendField(b, a.field, 1) -} - -//------------------------------------------------------------------------------ - -type Formatter struct { - namedParams map[string]interface{} -} - -func (f Formatter) String() string { - if len(f.namedParams) == 0 { - return "" - } - - var keys []string - for k, _ := range f.namedParams { - keys = append(keys, k) - } - sort.Strings(keys) - - var ss []string - for _, k := range keys { - ss = append(ss, fmt.Sprintf("%s=%v", k, f.namedParams[k])) - } - return " " + strings.Join(ss, " ") -} - -func (f Formatter) copy() Formatter { - var cp Formatter - for param, value := range f.namedParams { - cp.SetParam(param, value) - } - return cp -} - -func (f *Formatter) SetParam(param string, value interface{}) { - if f.namedParams == nil { - f.namedParams = make(map[string]interface{}) - } - f.namedParams[param] = value -} - -func (f *Formatter) WithParam(param string, value interface{}) Formatter { - cp := f.copy() - cp.SetParam(param, value) - return cp -} - -func (f Formatter) Param(param string) interface{} { - return f.namedParams[param] -} - -func (f Formatter) Append(dst []byte, src string, params ...interface{}) []byte { - if (params == nil && f.namedParams == nil) || strings.IndexByte(src, '?') == -1 { - return append(dst, src...) - } - return f.append(dst, parser.NewString(src), params) -} - -func (f Formatter) AppendBytes(dst, src []byte, params ...interface{}) []byte { - if (params == nil && f.namedParams == nil) || bytes.IndexByte(src, '?') == -1 { - return append(dst, src...) - } - return f.append(dst, parser.New(src), params) -} - -func (f Formatter) FormatQuery(dst []byte, query string, params ...interface{}) []byte { - return f.Append(dst, query, params...) -} - -func (f Formatter) append(dst []byte, p *parser.Parser, params []interface{}) []byte { - var paramsIndex int - var namedParamsOnce bool - var tableParams *tableParams - var model tableModel - - if len(params) > 0 { - var ok bool - model, ok = params[len(params)-1].(tableModel) - if ok { - params = params[:len(params)-1] - } - } - - for p.Valid() { - b, ok := p.ReadSep('?') - if !ok { - dst = append(dst, b...) - continue - } - if len(b) > 0 && b[len(b)-1] == '\\' { - dst = append(dst, b[:len(b)-1]...) - dst = append(dst, '?') - continue - } - dst = append(dst, b...) - - if id, numeric := p.ReadIdentifier(); id != "" { - if numeric { - idx, err := strconv.Atoi(id) - if err != nil { - goto restore_param - } - - if idx >= len(params) { - goto restore_param - } - - dst = f.appendParam(dst, params[idx]) - continue - } - - if f.namedParams != nil { - param, paramOK := f.namedParams[id] - if paramOK { - dst = f.appendParam(dst, param) - continue - } - } - - if !namedParamsOnce && len(params) > 0 { - namedParamsOnce = true - tableParams, _ = newTableParams(params[len(params)-1]) - } - - if tableParams != nil { - dst, ok = tableParams.AppendParam(dst, f, id) - if ok { - continue - } - } - - if model != nil { - dst, ok = model.AppendParam(dst, f, id) - if ok { - continue - } - } - - restore_param: - dst = append(dst, '?') - dst = append(dst, id...) - continue - } - - if paramsIndex >= len(params) { - dst = append(dst, '?') - continue - } - - param := params[paramsIndex] - paramsIndex++ - - dst = f.appendParam(dst, param) - } - - return dst -} - -type queryAppender interface { - AppendQuery(dst []byte) ([]byte, error) -} - -func (f Formatter) appendParam(b []byte, param interface{}) []byte { - switch param := param.(type) { - case queryAppender: - bb, err := param.AppendQuery(b) - if err != nil { - return types.AppendError(b, err) - } - return bb - case FormatAppender: - return param.AppendFormat(b, f) - default: - return types.Append(b, param, 1) - } -} diff --git a/vendor/github.com/go-pg/pg/orm/hook.go b/vendor/github.com/go-pg/pg/orm/hook.go deleted file mode 100644 index 45e589cea..000000000 --- a/vendor/github.com/go-pg/pg/orm/hook.go +++ /dev/null @@ -1,199 +0,0 @@ -package orm - -import ( - "reflect" -) - -type hookStubs struct{} - -func (hookStubs) AfterQuery(_ DB) error { - return nil -} - -func (hookStubs) BeforeSelectQuery(db DB, q *Query) (*Query, error) { - return q, nil -} - -func (hookStubs) AfterSelect(_ DB) error { - return nil -} - -func (hookStubs) BeforeInsert(_ DB) error { - return nil -} - -func (hookStubs) AfterInsert(_ DB) error { - return nil -} - -func (hookStubs) BeforeUpdate(_ DB) error { - return nil -} - -func (hookStubs) AfterUpdate(_ DB) error { - return nil -} - -func (hookStubs) BeforeDelete(_ DB) error { - return nil -} - -func (hookStubs) AfterDelete(_ DB) error { - return nil -} - -func callHookSlice(slice reflect.Value, ptr bool, db DB, hook func(reflect.Value, DB) error) error { - var firstErr error - for i := 0; i < slice.Len(); i++ { - var err error - if ptr { - err = hook(slice.Index(i), db) - } else { - err = hook(slice.Index(i).Addr(), db) - } - if err != nil && firstErr == nil { - firstErr = err - } - } - return firstErr -} - -//------------------------------------------------------------------------------ - -type afterQueryHook interface { - AfterQuery(db DB) error -} - -var afterQueryHookType = reflect.TypeOf((*afterQueryHook)(nil)).Elem() - -func callAfterQueryHook(v reflect.Value, db DB) error { - return v.Interface().(afterQueryHook).AfterQuery(db) -} - -func callAfterQueryHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callAfterQueryHook) -} - -//------------------------------------------------------------------------------ - -type beforeSelectQueryHook interface { - BeforeSelectQuery(db DB, q *Query) (*Query, error) -} - -var beforeSelectQueryHookType = reflect.TypeOf((*beforeSelectQueryHook)(nil)).Elem() - -func callBeforeSelectQueryHook(v reflect.Value, db DB, q *Query) (*Query, error) { - return v.Interface().(beforeSelectQueryHook).BeforeSelectQuery(db, q) -} - -//------------------------------------------------------------------------------ - -type afterSelectHook interface { - AfterSelect(db DB) error -} - -var afterSelectHookType = reflect.TypeOf((*afterSelectHook)(nil)).Elem() - -func callAfterSelectHook(v reflect.Value, db DB) error { - return v.Interface().(afterSelectHook).AfterSelect(db) -} - -func callAfterSelectHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callAfterSelectHook) -} - -//------------------------------------------------------------------------------ - -type beforeInsertHook interface { - BeforeInsert(db DB) error -} - -var beforeInsertHookType = reflect.TypeOf((*beforeInsertHook)(nil)).Elem() - -func callBeforeInsertHook(v reflect.Value, db DB) error { - return v.Interface().(beforeInsertHook).BeforeInsert(db) -} - -func callBeforeInsertHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callBeforeInsertHook) -} - -//------------------------------------------------------------------------------ - -type afterInsertHook interface { - AfterInsert(db DB) error -} - -var afterInsertHookType = reflect.TypeOf((*afterInsertHook)(nil)).Elem() - -func callAfterInsertHook(v reflect.Value, db DB) error { - return v.Interface().(afterInsertHook).AfterInsert(db) -} - -func callAfterInsertHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callAfterInsertHook) -} - -//------------------------------------------------------------------------------ - -type beforeUpdateHook interface { - BeforeUpdate(db DB) error -} - -var beforeUpdateHookType = reflect.TypeOf((*beforeUpdateHook)(nil)).Elem() - -func callBeforeUpdateHook(v reflect.Value, db DB) error { - return v.Interface().(beforeUpdateHook).BeforeUpdate(db) -} - -func callBeforeUpdateHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callBeforeUpdateHook) -} - -//------------------------------------------------------------------------------ - -type afterUpdateHook interface { - AfterUpdate(db DB) error -} - -var afterUpdateHookType = reflect.TypeOf((*afterUpdateHook)(nil)).Elem() - -func callAfterUpdateHook(v reflect.Value, db DB) error { - return v.Interface().(afterUpdateHook).AfterUpdate(db) -} - -func callAfterUpdateHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callAfterUpdateHook) -} - -//------------------------------------------------------------------------------ - -type beforeDeleteHook interface { - BeforeDelete(db DB) error -} - -var beforeDeleteHookType = reflect.TypeOf((*beforeDeleteHook)(nil)).Elem() - -func callBeforeDeleteHook(v reflect.Value, db DB) error { - return v.Interface().(beforeDeleteHook).BeforeDelete(db) -} - -func callBeforeDeleteHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callBeforeDeleteHook) -} - -//------------------------------------------------------------------------------ - -type afterDeleteHook interface { - AfterDelete(db DB) error -} - -var afterDeleteHookType = reflect.TypeOf((*afterDeleteHook)(nil)).Elem() - -func callAfterDeleteHook(v reflect.Value, db DB) error { - return v.Interface().(afterDeleteHook).AfterDelete(db) -} - -func callAfterDeleteHookSlice(slice reflect.Value, ptr bool, db DB) error { - return callHookSlice(slice, ptr, db, callAfterDeleteHook) -} diff --git a/vendor/github.com/go-pg/pg/orm/inflection.go b/vendor/github.com/go-pg/pg/orm/inflection.go deleted file mode 100644 index 9ff8bd624..000000000 --- a/vendor/github.com/go-pg/pg/orm/inflection.go +++ /dev/null @@ -1,17 +0,0 @@ -package orm - -import ( - "github.com/jinzhu/inflection" -) - -var tableNameInflector func(string) string - -func init() { - SetTableNameInflector(inflection.Plural) -} - -// SetTableNameInflector overrides the default func that pluralizes -// model name to get table name, e.g. my_article becomes my_articles. -func SetTableNameInflector(fn func(string) string) { - tableNameInflector = fn -} diff --git a/vendor/github.com/go-pg/pg/orm/insert.go b/vendor/github.com/go-pg/pg/orm/insert.go deleted file mode 100644 index 559072f97..000000000 --- a/vendor/github.com/go-pg/pg/orm/insert.go +++ /dev/null @@ -1,157 +0,0 @@ -package orm - -import ( - "errors" - "fmt" - "reflect" -) - -func Insert(db DB, model ...interface{}) error { - _, err := NewQuery(db, model...).Insert() - return err -} - -type insertQuery struct { - q *Query - returningFields []*Field -} - -var _ QueryAppender = (*insertQuery)(nil) - -func (q *insertQuery) Copy() QueryAppender { - return &insertQuery{ - q: q.q.Copy(), - } -} - -func (q *insertQuery) Query() *Query { - return q.q -} - -func (q *insertQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - if q.q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - - table := q.q.model.Table() - value := q.q.model.Value() - var err error - - if len(q.q.with) > 0 { - b, err = q.q.appendWith(b) - if err != nil { - return nil, err - } - } - - b = append(b, "INSERT INTO "...) - if q.q.onConflict != nil { - b = q.q.appendFirstTableWithAlias(b) - } else { - b = q.q.appendFirstTable(b) - } - - if q.q.hasMultiTables() { - if q.q.columns != nil { - b = append(b, " ("...) - b = q.q.appendColumns(b) - b = append(b, ")"...) - } - b = append(b, " SELECT * FROM "...) - b = q.q.appendOtherTables(b) - } else { - fields, err := q.q.getFields() - if err != nil { - return nil, err - } - - if len(fields) == 0 { - fields = table.Fields - } - - b = append(b, " ("...) - b = appendColumns(b, "", fields) - b = append(b, ") VALUES ("...) - if value.Kind() == reflect.Struct { - b = q.appendValues(b, fields, value) - } else { - if value.Len() == 0 { - err = fmt.Errorf("pg: can't bulk-insert empty slice %s", value.Type()) - return nil, err - } - - for i := 0; i < value.Len(); i++ { - el := indirect(value.Index(i)) - b = q.appendValues(b, fields, el) - if i != value.Len()-1 { - b = append(b, "), ("...) - } - } - } - b = append(b, ")"...) - } - - if q.q.onConflict != nil { - b = append(b, " ON CONFLICT "...) - b = q.q.onConflict.AppendFormat(b, q.q) - - if q.q.onConflictDoUpdate() { - if len(q.q.set) > 0 { - b = q.q.appendSet(b) - } - - if len(q.q.updWhere) > 0 { - b = append(b, " WHERE "...) - b = q.q.appendUpdWhere(b) - } - } - } - - if len(q.q.returning) > 0 { - b = q.q.appendReturning(b) - } else if len(q.returningFields) > 0 { - b = appendReturningFields(b, q.returningFields) - } - - return b, nil -} - -func (q *insertQuery) appendValues(b []byte, fields []*Field, v reflect.Value) []byte { - for i, f := range fields { - if i > 0 { - b = append(b, ", "...) - } - - app, ok := q.q.modelValues[f.SQLName] - if ok { - b = app.AppendFormat(b, q.q) - continue - } - - if (f.Default != "" || f.OmitZero()) && f.IsZero(v) { - b = append(b, "DEFAULT"...) - q.addReturningField(f) - } else { - b = f.AppendValue(b, v, 1) - } - } - return b -} - -func (ins *insertQuery) addReturningField(field *Field) { - for _, f := range ins.returningFields { - if f == field { - return - } - } - ins.returningFields = append(ins.returningFields, field) -} - -func appendReturningFields(b []byte, fields []*Field) []byte { - b = append(b, " RETURNING "...) - b = appendColumns(b, "", fields) - return b -} diff --git a/vendor/github.com/go-pg/pg/orm/model.go b/vendor/github.com/go-pg/pg/orm/model.go deleted file mode 100644 index 1ecb3c9fc..000000000 --- a/vendor/github.com/go-pg/pg/orm/model.go +++ /dev/null @@ -1,110 +0,0 @@ -package orm - -import ( - "database/sql" - "errors" - "fmt" - "reflect" - - "github.com/go-pg/pg/types" -) - -type useQueryOne interface { - useQueryOne() bool -} - -type HooklessModel interface { - // Init is responsible to initialize/reset model state. - // It is called only once no matter how many rows - // were returned by database. - Init() error - - // NewModel returns ColumnScanner that is used to scan columns - // from the current row. It is called once for every row. - NewModel() ColumnScanner - - // AddModel adds ColumnScanner created by NewModel to the Collection. - AddModel(ColumnScanner) error - - ColumnScanner -} - -type Model interface { - HooklessModel - - AfterQuery(DB) error - - BeforeSelectQuery(DB, *Query) (*Query, error) - AfterSelect(DB) error - - BeforeInsert(DB) error - AfterInsert(DB) error - - BeforeUpdate(DB) error - AfterUpdate(DB) error - - BeforeDelete(DB) error - AfterDelete(DB) error -} - -func NewModel(values ...interface{}) (Model, error) { - if len(values) > 1 { - return Scan(values...), nil - } - - v0 := values[0] - switch v0 := v0.(type) { - case Model: - return v0, nil - case HooklessModel: - return newModelWithHookStubs(v0), nil - case sql.Scanner: - return Scan(v0), nil - } - - v := reflect.ValueOf(v0) - if !v.IsValid() { - return nil, errors.New("pg: Model(nil)") - } - if v.Kind() != reflect.Ptr { - return nil, fmt.Errorf("pg: Model(non-pointer %T)", v0) - } - v = v.Elem() - - switch v.Kind() { - case reflect.Struct: - return newStructTableModelValue(v), nil - case reflect.Slice: - typ := v.Type() - structType := indirectType(typ.Elem()) - if structType.Kind() == reflect.Struct && structType != timeType { - m := sliceTableModel{ - structTableModel: structTableModel{ - table: GetTable(structType), - root: v, - }, - slice: v, - } - m.init(typ) - return &m, nil - } else { - return &sliceModel{ - slice: v, - scan: types.Scanner(structType), - }, nil - } - } - - return Scan(v0), nil -} - -type modelWithHookStubs struct { - hookStubs - HooklessModel -} - -func newModelWithHookStubs(m HooklessModel) Model { - return modelWithHookStubs{ - HooklessModel: m, - } -} diff --git a/vendor/github.com/go-pg/pg/orm/model_discard.go b/vendor/github.com/go-pg/pg/orm/model_discard.go deleted file mode 100644 index 3b7b4389f..000000000 --- a/vendor/github.com/go-pg/pg/orm/model_discard.go +++ /dev/null @@ -1,23 +0,0 @@ -package orm - -type Discard struct { - hookStubs -} - -var _ Model = (*Discard)(nil) - -func (Discard) Init() error { - return nil -} - -func (m Discard) NewModel() ColumnScanner { - return m -} - -func (m Discard) AddModel(ColumnScanner) error { - return nil -} - -func (m Discard) ScanColumn(colIdx int, colName string, b []byte) error { - return nil -} diff --git a/vendor/github.com/go-pg/pg/orm/model_slice.go b/vendor/github.com/go-pg/pg/orm/model_slice.go deleted file mode 100644 index 3e79be2fc..000000000 --- a/vendor/github.com/go-pg/pg/orm/model_slice.go +++ /dev/null @@ -1,35 +0,0 @@ -package orm - -import ( - "reflect" - - "github.com/go-pg/pg/internal" -) - -type sliceModel struct { - Discard - slice reflect.Value - nextElem func() reflect.Value - scan func(reflect.Value, []byte) error -} - -var _ Model = (*sliceModel)(nil) - -func (m *sliceModel) Init() error { - if m.slice.IsValid() && m.slice.Len() > 0 { - m.slice.Set(m.slice.Slice(0, 0)) - } - return nil -} - -func (m *sliceModel) NewModel() ColumnScanner { - return m -} - -func (m *sliceModel) ScanColumn(colIdx int, _ string, b []byte) error { - if m.nextElem == nil { - m.nextElem = internal.MakeSliceNextElemFunc(m.slice) - } - v := m.nextElem() - return m.scan(v, b) -} diff --git a/vendor/github.com/go-pg/pg/orm/model_table.go b/vendor/github.com/go-pg/pg/orm/model_table.go deleted file mode 100644 index f67b9fb75..000000000 --- a/vendor/github.com/go-pg/pg/orm/model_table.go +++ /dev/null @@ -1,109 +0,0 @@ -package orm - -import ( - "errors" - "fmt" - "reflect" -) - -type tableModel interface { - Model - - Table() *Table - Relation() *Relation - AppendParam([]byte, QueryFormatter, string) ([]byte, bool) - - Join(string, func(*Query) (*Query, error)) *join - GetJoin(string) *join - GetJoins() []join - AddJoin(join) *join - - Root() reflect.Value - Index() []int - ParentIndex() []int - Mount(reflect.Value) - Kind() reflect.Kind - Value() reflect.Value - - setDeletedAt() - scanColumn(int, string, []byte) (bool, error) -} - -func newTableModel(value interface{}) (tableModel, error) { - if value, ok := value.(tableModel); ok { - return value, nil - } - - v := reflect.ValueOf(value) - if !v.IsValid() { - return nil, errors.New("pg: Model(nil)") - } - if v.Kind() != reflect.Ptr { - return nil, fmt.Errorf("pg: Model(non-pointer %T)", value) - } - - if v.IsNil() { - typ := v.Type().Elem() - if typ.Kind() == reflect.Struct { - return newStructTableModelType(typ), nil - } - return nil, errors.New("pg: Model(nil)") - } - - return newTableModelValue(v.Elem()) -} - -func newTableModelValue(v reflect.Value) (tableModel, error) { - switch v.Kind() { - case reflect.Struct: - return newStructTableModelValue(v), nil - case reflect.Slice: - structType := sliceElemType(v) - if structType.Kind() == reflect.Struct { - m := sliceTableModel{ - structTableModel: structTableModel{ - table: GetTable(structType), - root: v, - }, - slice: v, - } - m.init(v.Type()) - return &m, nil - } - } - - return nil, fmt.Errorf("pg: Model(unsupported %s)", v.Type()) -} - -func newTableModelIndex(root reflect.Value, index []int, rel *Relation) (tableModel, error) { - typ := typeByIndex(root.Type(), index) - - if typ.Kind() == reflect.Struct { - return &structTableModel{ - table: GetTable(typ), - rel: rel, - - root: root, - index: index, - }, nil - } - - if typ.Kind() == reflect.Slice { - structType := indirectType(typ.Elem()) - if structType.Kind() == reflect.Struct { - m := sliceTableModel{ - structTableModel: structTableModel{ - table: GetTable(structType), - rel: rel, - - root: root, - index: index, - }, - } - m.init(typ) - return &m, nil - } - } - - return nil, fmt.Errorf("pg: NewModel(%s)", typ) -} diff --git a/vendor/github.com/go-pg/pg/orm/model_table_m2m.go b/vendor/github.com/go-pg/pg/orm/model_table_m2m.go deleted file mode 100644 index 98bb68612..000000000 --- a/vendor/github.com/go-pg/pg/orm/model_table_m2m.go +++ /dev/null @@ -1,135 +0,0 @@ -package orm - -import ( - "fmt" - "reflect" -) - -type m2mModel struct { - *sliceTableModel - baseTable *Table - rel *Relation - - buf []byte - dstValues map[string][]reflect.Value - columns map[string]string -} - -var _ tableModel = (*m2mModel)(nil) - -func newM2MModel(j *join) *m2mModel { - baseTable := j.BaseModel.Table() - joinModel := j.JoinModel.(*sliceTableModel) - dstValues := dstValues(joinModel, baseTable.PKs) - if len(dstValues) == 0 { - return nil - } - m := &m2mModel{ - sliceTableModel: joinModel, - baseTable: baseTable, - rel: j.Rel, - - dstValues: dstValues, - columns: make(map[string]string), - } - if !m.sliceOfPtr { - m.strct = reflect.New(m.table.Type).Elem() - } - return m -} - -func (m *m2mModel) NewModel() ColumnScanner { - if m.sliceOfPtr { - m.strct = reflect.New(m.table.Type).Elem() - } else { - m.strct.Set(m.table.zeroStruct) - } - m.structInited = false - m.structTableModel.NewModel() - return m -} - -func (m *m2mModel) AddModel(model ColumnScanner) error { - m.buf = modelIdMap(m.buf[:0], m.columns, m.rel.BaseFKs) - dstValues, ok := m.dstValues[string(m.buf)] - if !ok { - return fmt.Errorf( - "pg: relation=%q has no base %s with id=%q (check join conditions)", - m.rel.Field.GoName, m.baseTable, m.buf) - } - - for _, v := range dstValues { - if m.sliceOfPtr { - v.Set(reflect.Append(v, m.strct.Addr())) - } else { - v.Set(reflect.Append(v, m.strct)) - } - } - - return nil -} - -func modelIdMap(b []byte, m map[string]string, columns []string) []byte { - for i, col := range columns { - if i > 0 { - b = append(b, ',') - } - b = append(b, m[col]...) - } - return b -} - -func (m *m2mModel) AfterQuery(db DB) error { - if !m.rel.JoinTable.HasFlag(AfterQueryHookFlag) { - return nil - } - - var retErr error - for _, slices := range m.dstValues { - for _, slice := range slices { - err := callAfterQueryHookSlice(slice, m.sliceOfPtr, db) - if err != nil && retErr == nil { - retErr = err - } - } - } - return retErr -} - -func (m *m2mModel) AfterSelect(db DB) error { - return nil -} - -func (m *m2mModel) BeforeInsert(db DB) error { - return nil -} - -func (m *m2mModel) AfterInsert(db DB) error { - return nil -} - -func (m *m2mModel) BeforeUpdate(db DB) error { - return nil -} - -func (m *m2mModel) AfterUpdate(db DB) error { - return nil -} - -func (m *m2mModel) BeforeDelete(db DB) error { - return nil -} - -func (m *m2mModel) AfterDelete(db DB) error { - return nil -} - -func (m *m2mModel) ScanColumn(colIdx int, colName string, b []byte) error { - ok, err := m.sliceTableModel.scanColumn(colIdx, colName, b) - if ok { - return err - } - - m.columns[colName] = string(b) - return nil -} diff --git a/vendor/github.com/go-pg/pg/orm/model_table_many.go b/vendor/github.com/go-pg/pg/orm/model_table_many.go deleted file mode 100644 index 41af7ee2d..000000000 --- a/vendor/github.com/go-pg/pg/orm/model_table_many.go +++ /dev/null @@ -1,113 +0,0 @@ -package orm - -import ( - "fmt" - "reflect" -) - -type manyModel struct { - *sliceTableModel - baseTable *Table - rel *Relation - - buf []byte - dstValues map[string][]reflect.Value -} - -var _ tableModel = (*manyModel)(nil) - -func newManyModel(j *join) *manyModel { - baseTable := j.BaseModel.Table() - joinModel := j.JoinModel.(*sliceTableModel) - dstValues := dstValues(joinModel, j.Rel.FKValues) - if len(dstValues) == 0 { - return nil - } - m := manyModel{ - sliceTableModel: joinModel, - baseTable: baseTable, - rel: j.Rel, - - dstValues: dstValues, - } - if !m.sliceOfPtr { - m.strct = reflect.New(m.table.Type).Elem() - } - return &m -} - -func (m *manyModel) NewModel() ColumnScanner { - if m.sliceOfPtr { - m.strct = reflect.New(m.table.Type).Elem() - } else { - m.strct.Set(m.table.zeroStruct) - } - m.structInited = false - m.structTableModel.NewModel() - return m -} - -func (m *manyModel) AddModel(model ColumnScanner) error { - m.buf = modelId(m.buf[:0], m.strct, m.rel.FKs) - dstValues, ok := m.dstValues[string(m.buf)] - if !ok { - return fmt.Errorf( - "pg: relation=%q has no base model=%q with id=%q (check join conditions)", - m.rel.Field.GoName, m.baseTable.TypeName, m.buf) - } - - for _, v := range dstValues { - if m.sliceOfPtr { - v.Set(reflect.Append(v, m.strct.Addr())) - } else { - v.Set(reflect.Append(v, m.strct)) - } - } - - return nil -} - -func (m *manyModel) AfterQuery(db DB) error { - if !m.rel.JoinTable.HasFlag(AfterQueryHookFlag) { - return nil - } - - var retErr error - for _, slices := range m.dstValues { - for _, slice := range slices { - err := callAfterQueryHookSlice(slice, m.sliceOfPtr, db) - if err != nil && retErr == nil { - retErr = err - } - } - } - return retErr -} - -func (m *manyModel) AfterSelect(db DB) error { - return nil -} - -func (m *manyModel) BeforeInsert(db DB) error { - return nil -} - -func (m *manyModel) AfterInsert(db DB) error { - return nil -} - -func (m *manyModel) BeforeUpdate(db DB) error { - return nil -} - -func (m *manyModel) AfterUpdate(db DB) error { - return nil -} - -func (m *manyModel) BeforeDelete(db DB) error { - return nil -} - -func (m *manyModel) AfterDelete(db DB) error { - return nil -} diff --git a/vendor/github.com/go-pg/pg/orm/model_table_slice.go b/vendor/github.com/go-pg/pg/orm/model_table_slice.go deleted file mode 100644 index 8b63ac6d9..000000000 --- a/vendor/github.com/go-pg/pg/orm/model_table_slice.go +++ /dev/null @@ -1,152 +0,0 @@ -package orm - -import ( - "reflect" - "time" -) - -type sliceTableModel struct { - structTableModel - - slice reflect.Value - sliceOfPtr bool -} - -var _ tableModel = (*sliceTableModel)(nil) - -func (m *sliceTableModel) init(sliceType reflect.Type) { - switch sliceType.Elem().Kind() { - case reflect.Ptr, reflect.Interface: - m.sliceOfPtr = true - } -} - -func (sliceTableModel) useQueryOne() {} - -func (m *sliceTableModel) AppendParam(b []byte, f QueryFormatter, name string) ([]byte, bool) { - if field, ok := m.table.FieldsMap[name]; ok { - b = append(b, "_data."...) - b = append(b, field.Column...) - return b, true - } - - return m.structTableModel.AppendParam(b, f, name) -} - -func (m *sliceTableModel) Join(name string, apply func(*Query) (*Query, error)) *join { - return m.join(m.Value(), name, apply) -} - -func (m *sliceTableModel) Bind(bind reflect.Value) { - m.slice = bind.Field(m.index[len(m.index)-1]) -} - -func (m *sliceTableModel) Kind() reflect.Kind { - return reflect.Slice -} - -func (m *sliceTableModel) Value() reflect.Value { - return m.slice -} - -func (m *sliceTableModel) Init() error { - if m.slice.IsValid() && m.slice.Len() > 0 { - m.slice.Set(m.slice.Slice(0, 0)) - } - return nil -} - -func (m *sliceTableModel) NewModel() ColumnScanner { - m.strct = m.nextElem() - m.structInited = false - return m -} - -func (m *sliceTableModel) AfterQuery(db DB) error { - if !m.table.HasFlag(AfterQueryHookFlag) { - return nil - } - return callAfterQueryHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) AfterSelect(db DB) error { - if !m.table.HasFlag(AfterSelectHookFlag) { - return nil - } - return callAfterSelectHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) BeforeInsert(db DB) error { - if !m.table.HasFlag(BeforeInsertHookFlag) { - return nil - } - return callBeforeInsertHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) AfterInsert(db DB) error { - if !m.table.HasFlag(AfterInsertHookFlag) { - return nil - } - return callAfterInsertHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) BeforeUpdate(db DB) error { - if !m.table.HasFlag(BeforeUpdateHookFlag) { - return nil - } - return callBeforeUpdateHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) AfterUpdate(db DB) error { - if !m.table.HasFlag(AfterUpdateHookFlag) { - return nil - } - return callAfterUpdateHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) BeforeDelete(db DB) error { - if !m.table.HasFlag(BeforeDeleteHookFlag) { - return nil - } - return callBeforeDeleteHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) AfterDelete(db DB) error { - if !m.table.HasFlag(AfterDeleteHookFlag) { - return nil - } - return callAfterDeleteHookSlice(m.slice, m.sliceOfPtr, db) -} - -func (m *sliceTableModel) nextElem() reflect.Value { - if m.slice.Len() < m.slice.Cap() { - m.slice.Set(m.slice.Slice(0, m.slice.Len()+1)) - elem := m.slice.Index(m.slice.Len() - 1) - if m.sliceOfPtr { - if elem.IsNil() { - elem.Set(reflect.New(elem.Type().Elem())) - } - return elem.Elem() - } - return elem - } - - if m.sliceOfPtr { - elem := reflect.New(m.table.Type) - m.slice.Set(reflect.Append(m.slice, elem)) - return elem.Elem() - } - - m.slice.Set(reflect.Append(m.slice, m.table.zeroStruct)) - return m.slice.Index(m.slice.Len() - 1) -} - -func (m *sliceTableModel) setDeletedAt() { - field := m.table.FieldsMap["deleted_at"] - now := time.Now() - for i := 0; i < m.slice.Len(); i++ { - strct := indirect(m.slice.Index(i)) - value := field.Value(strct) - value.Set(reflect.ValueOf(now)) - } -} diff --git a/vendor/github.com/go-pg/pg/orm/orm.go b/vendor/github.com/go-pg/pg/orm/orm.go deleted file mode 100644 index 02d2d3ab9..000000000 --- a/vendor/github.com/go-pg/pg/orm/orm.go +++ /dev/null @@ -1,46 +0,0 @@ -package orm - -import ( - "context" - "io" -) - -// ColumnScanner is used to scan column values. -type ColumnScanner interface { - // Scan assigns a column value from a row. - // - // An error should be returned if the value can not be stored - // without loss of information. - ScanColumn(colIdx int, colName string, b []byte) error -} - -type QueryAppender interface { - Copy() QueryAppender - Query() *Query - AppendQuery(dst []byte) ([]byte, error) -} - -type QueryFormatter interface { - FormatQuery(b []byte, query string, params ...interface{}) []byte -} - -// DB is a common interface for pg.DB and pg.Tx types. -type DB interface { - Model(model ...interface{}) *Query - Select(model interface{}) error - Insert(model ...interface{}) error - Update(model interface{}) error - Delete(model interface{}) error - ForceDelete(model interface{}) error - - Exec(query interface{}, params ...interface{}) (Result, error) - ExecOne(query interface{}, params ...interface{}) (Result, error) - Query(coll, query interface{}, params ...interface{}) (Result, error) - QueryOne(model, query interface{}, params ...interface{}) (Result, error) - - CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error) - CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error) - - Context() context.Context - QueryFormatter -} diff --git a/vendor/github.com/go-pg/pg/orm/pager.go b/vendor/github.com/go-pg/pg/orm/pager.go deleted file mode 100644 index 10ec72732..000000000 --- a/vendor/github.com/go-pg/pg/orm/pager.go +++ /dev/null @@ -1,111 +0,0 @@ -package orm - -import ( - "net/url" -) - -type Pager struct { - Limit int - Offset int - - // Default max limit is 1000. - MaxLimit int - // Default max offset is 1000000. - MaxOffset int - - stickyErr error -} - -func NewPager(values url.Values) *Pager { - p := new(Pager) - p.SetURLValues(values) - return p -} - -func (p *Pager) SetURLValues(urlValues url.Values) { - values := URLValues(urlValues) - - if values.Has("limit") { - limit, err := values.Int("limit") - if err != nil { - p.stickyErr = err - return - } - p.Limit = int(limit) - } - - if values.Has("page") { - page, err := values.Int("page") - if err != nil { - p.stickyErr = err - return - } - p.SetPage(int(page)) - } -} - -func (p *Pager) maxLimit() int { - if p.MaxLimit > 0 { - return p.MaxLimit - } - return 1000 -} - -func (p *Pager) maxOffset() int { - if p.MaxOffset > 0 { - return p.MaxOffset - } - return 1000000 -} - -func (p *Pager) GetLimit() int { - const defaultLimit = 100 - - if p.Limit < 0 { - return p.Limit - } - if p.Limit == 0 { - return defaultLimit - } - if p.Limit > p.maxLimit() { - return p.maxLimit() - } - return p.Limit -} - -func (p *Pager) GetOffset() int { - if p.Offset > p.maxOffset() { - return p.maxOffset() - } - return p.Offset -} - -func (p *Pager) SetPage(page int) { - if page < 1 { - page = 1 - } - p.Offset = (page - 1) * p.GetLimit() -} - -func (p *Pager) GetPage() int { - return (p.GetOffset() / p.GetLimit()) + 1 -} - -func (p *Pager) Paginate(q *Query) (*Query, error) { - if p == nil { - return q, nil - } - if p.stickyErr != nil { - return nil, p.stickyErr - } - - q = q.Limit(p.GetLimit()).Offset(p.GetOffset()) - return q, nil -} - -// Pagination is used with Query.Apply to set LIMIT and OFFSET from the URL values: -// - ?limit=10 - sets q.Limit(10), max limit is 1000. -// - ?page=5 - sets q.Offset((page - 1) * limit), max offset is 1000000. -func Pagination(values url.Values) func(*Query) (*Query, error) { - return NewPager(values).Paginate -} diff --git a/vendor/github.com/go-pg/pg/orm/query.go b/vendor/github.com/go-pg/pg/orm/query.go deleted file mode 100644 index b44bc7e14..000000000 --- a/vendor/github.com/go-pg/pg/orm/query.go +++ /dev/null @@ -1,1302 +0,0 @@ -package orm - -import ( - "errors" - "fmt" - "io" - "reflect" - "strings" - "sync" - "time" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/types" -) - -type withQuery struct { - name string - query *Query -} - -type joinQuery struct { - join *queryParamsAppender - on []*condAppender -} - -func (q *joinQuery) AppendOn(app *condAppender) { - q.on = append(q.on, app) -} - -type Query struct { - db DB - stickyErr error - - model tableModel - ignoreModel bool - deleted bool - - with []withQuery - tables []FormatAppender - columns []FormatAppender - set []FormatAppender - modelValues map[string]*queryParamsAppender - where []sepFormatAppender - updWhere []sepFormatAppender - joins []*joinQuery - joinAppendOn func(app *condAppender) - group []FormatAppender - having []*queryParamsAppender - order []FormatAppender - onConflict *queryParamsAppender - returning []*queryParamsAppender - limit int - offset int - selFor *queryParamsAppender -} - -var _ queryAppender = (*Query)(nil) - -func NewQuery(db DB, model ...interface{}) *Query { - return (&Query{}).DB(db).Model(model...) -} - -// New returns new zero Query binded to the current db and model. -func (q *Query) New() *Query { - return &Query{ - db: q.db, - model: q.model, - ignoreModel: true, - deleted: q.deleted, - } -} - -func (q *Query) AppendQuery(b []byte) ([]byte, error) { - return selectQuery{q: q}.AppendQuery(b) -} - -// Copy returns copy of the Query. -func (q *Query) Copy() *Query { - var modelValues map[string]*queryParamsAppender - if len(q.modelValues) > 0 { - modelValues = make(map[string]*queryParamsAppender, len(q.modelValues)) - for k, v := range q.modelValues { - modelValues[k] = v - } - } - - copy := &Query{ - db: q.db, - stickyErr: q.stickyErr, - - model: q.model, - ignoreModel: q.ignoreModel, - deleted: q.deleted, - - tables: q.tables[:len(q.tables):len(q.tables)], - columns: q.columns[:len(q.columns):len(q.columns)], - set: q.set[:len(q.set):len(q.set)], - modelValues: modelValues, - where: q.where[:len(q.where):len(q.where)], - updWhere: q.updWhere[:len(q.updWhere):len(q.updWhere)], - joins: q.joins[:len(q.joins):len(q.joins)], - group: q.group[:len(q.group):len(q.group)], - having: q.having[:len(q.having):len(q.having)], - order: q.order[:len(q.order):len(q.order)], - onConflict: q.onConflict, - returning: q.returning[:len(q.returning):len(q.returning)], - limit: q.limit, - offset: q.offset, - selFor: q.selFor, - } - for _, with := range q.with { - copy = copy.With(with.name, with.query.Copy()) - } - return copy -} - -func (q *Query) err(err error) *Query { - if q.stickyErr == nil { - q.stickyErr = err - } - return q -} - -func (q *Query) DB(db DB) *Query { - q.db = db - for _, with := range q.with { - with.query.db = db - } - return q -} - -func (q *Query) Model(model ...interface{}) *Query { - var err error - switch l := len(model); { - case l == 0: - q.model = nil - case l == 1: - q.model, err = newTableModel(model[0]) - case l > 1: - q.model, err = newTableModel(&model) - } - if err != nil { - q = q.err(err) - } - if q.ignoreModel { - q.ignoreModel = false - } - return q -} - -func (q *Query) softDelete() bool { - if q.model != nil { - return q.model.Table().HasFlag(softDelete) - } - return false -} - -// Deleted adds `WHERE deleted_at IS NOT NULL` clause for soft deleted models. -func (q *Query) Deleted() *Query { - if q.model != nil { - if err := q.model.Table().mustSoftDelete(); err != nil { - return q.err(err) - } - } - q.deleted = true - return q -} - -// With adds subq as common table expression with the given name. -func (q *Query) With(name string, subq *Query) *Query { - q.with = append(q.with, withQuery{name, subq}) - return q -} - -// WrapWith creates new Query and adds to it current query as -// common table expression with the given name. -func (q *Query) WrapWith(name string) *Query { - wrapper := q.New() - wrapper.with = q.with - q.with = nil - wrapper = wrapper.With(name, q) - return wrapper -} - -func (q *Query) Table(tables ...string) *Query { - for _, table := range tables { - q.tables = append(q.tables, fieldAppender{table}) - } - return q -} - -func (q *Query) TableExpr(expr string, params ...interface{}) *Query { - q.tables = append(q.tables, &queryParamsAppender{expr, params}) - return q -} - -// Column adds a column to the Query quoting it according to PostgreSQL rules. Does not expand params like ?TableAlias etc. -// ColumnExpr can be used to bypass quoting restriction or for params expansion. Column name can be: -// - column_name, -// - table_alias.column_name, -// - table_alias.*. -func (q *Query) Column(columns ...string) *Query { - for _, column := range columns { - if column == "_" { - if q.columns == nil { - q.columns = make([]FormatAppender, 0) - } - continue - } - - if q.model != nil { - if j := q.model.Join(column, nil); j != nil { - continue - } - } - - q.columns = append(q.columns, fieldAppender{column}) - } - return q -} - -// ColumnExpr adds column expression to the Query. -func (q *Query) ColumnExpr(expr string, params ...interface{}) *Query { - q.columns = append(q.columns, &queryParamsAppender{expr, params}) - return q -} - -// ExcludeColumn excludes a column from the list of to be selected columns. -func (q *Query) ExcludeColumn(columns ...string) *Query { - if q.columns == nil { - for _, f := range q.model.Table().Fields { - q.columns = append(q.columns, fieldAppender{f.SQLName}) - } - } - - for _, col := range columns { - if !q.excludeColumn(col) { - return q.err(fmt.Errorf("pg: can't find column=%q", col)) - } - } - return q -} - -func (q *Query) excludeColumn(column string) bool { - for i := 0; i < len(q.columns); i++ { - app, ok := q.columns[i].(fieldAppender) - if ok && app.field == column { - q.columns = append(q.columns[:i], q.columns[i+1:]...) - return true - } - } - return false -} - -func (q *Query) getFields() ([]*Field, error) { - return q._getFields(false) -} - -func (q *Query) getDataFields() ([]*Field, error) { - return q._getFields(true) -} - -func (q *Query) _getFields(omitPKs bool) ([]*Field, error) { - table := q.model.Table() - var columns []*Field - for _, col := range q.columns { - f, ok := col.(fieldAppender) - if !ok { - continue - } - - field, err := table.GetField(f.field) - if err != nil { - return nil, err - } - - if omitPKs && field.HasFlag(PrimaryKeyFlag) { - continue - } - - columns = append(columns, field) - } - return columns, nil -} - -// Relation adds a relation to the query. Relation name can be: -// - RelationName to select all columns, -// - RelationName.column_name, -// - RelationName._ to join relation without selecting relation columns. -func (q *Query) Relation(name string, apply ...func(*Query) (*Query, error)) *Query { - var fn func(*Query) (*Query, error) - if len(apply) == 1 { - fn = apply[0] - } else if len(apply) > 1 { - panic("only one apply function is supported") - } - - join := q.model.Join(name, fn) - if join == nil { - return q.err(fmt.Errorf("%s does not have relation=%q", - q.model.Table(), name)) - } - - if fn == nil { - return q - } - - switch join.Rel.Type { - case HasOneRelation, BelongsToRelation: - q.joinAppendOn = join.AppendOn - return q.Apply(fn) - default: - q.joinAppendOn = nil - return q - } -} - -func (q *Query) Set(set string, params ...interface{}) *Query { - q.set = append(q.set, &queryParamsAppender{set, params}) - return q -} - -// Value overwrites model value for the column in INSERT and UPDATE queries. -func (q *Query) Value(column string, value string, params ...interface{}) *Query { - if !q.hasModel() { - q.err(errors.New("pg: Model(nil)")) - return q - } - - table := q.model.Table() - if _, ok := table.FieldsMap[column]; !ok { - q.err(fmt.Errorf("%s does not have column=%q", table, column)) - return q - } - - if q.modelValues == nil { - q.modelValues = make(map[string]*queryParamsAppender) - } - q.modelValues[column] = &queryParamsAppender{value, params} - return q -} - -func (q *Query) Where(condition string, params ...interface{}) *Query { - q.addWhere(&condAppender{ - sep: " AND ", - cond: condition, - params: params, - }) - return q -} - -func (q *Query) WhereOr(condition string, params ...interface{}) *Query { - q.addWhere(&condAppender{ - sep: " OR ", - cond: condition, - params: params, - }) - return q -} - -// WhereGroup encloses conditions added in the function in parentheses. -// -// q.Where("TRUE"). -// WhereGroup(func(q *orm.Query) (*orm.Query, error)) { -// q = q.WhereOr("FALSE").WhereOr("TRUE"). -// return q, nil -// }) -// -// generates -// -// WHERE TRUE AND (FALSE OR TRUE) -func (q *Query) WhereGroup(fn func(*Query) (*Query, error)) *Query { - return q.whereGroup(" AND ", fn) -} - -// WhereOrGroup encloses conditions added in the function in parentheses. -// -// q.Where("TRUE"). -// WhereOrGroup(func(q *orm.Query) (*orm.Query, error)) { -// q = q.Where("FALSE").Where("TRUE"). -// return q, nil -// }) -// -// generates -// -// WHERE TRUE OR (FALSE AND TRUE) -func (q *Query) WhereOrGroup(fn func(*Query) (*Query, error)) *Query { - return q.whereGroup(" OR ", fn) -} - -func (q *Query) whereGroup(conj string, fn func(*Query) (*Query, error)) *Query { - saved := q.where - q.where = nil - - newq, err := fn(q) - if err != nil { - q.err(err) - return q - } - - if len(newq.where) == 0 { - newq.where = saved - return newq - } - - f := &condGroupAppender{ - sep: conj, - cond: newq.where, - } - newq.where = saved - newq.addWhere(f) - - return newq -} - -// WhereIn is a shortcut for Where and pg.In to work with IN operator: -// -// WhereIn("id IN (?)", 1, 2, 3) -func (q *Query) WhereIn(where string, values ...interface{}) *Query { - return q.Where(where, types.InSlice(values)) -} - -func (q *Query) addWhere(f sepFormatAppender) { - if q.onConflictDoUpdate() { - q.updWhere = append(q.updWhere, f) - } else { - q.where = append(q.where, f) - } -} - -// WherePK adds condition based on the model primary key. -// Typically it is the same as: -// -// Where("id = ?id") -func (q *Query) WherePK() *Query { - if !q.hasModel() { - q.err(errors.New("pg: Model(nil)")) - return q - } - if q.model.Kind() == reflect.Slice { - q.err(errors.New("pg: WherePK requires struct Model")) - return q - } - if err := q.model.Table().checkPKs(); err != nil { - q.err(err) - return q - } - q.where = append(q.where, wherePKQuery{q}) - return q -} - -func (q *Query) Join(join string, params ...interface{}) *Query { - j := &joinQuery{ - join: &queryParamsAppender{join, params}, - } - q.joins = append(q.joins, j) - q.joinAppendOn = j.AppendOn - return q -} - -// JoinOn appends join condition to the last join. -func (q *Query) JoinOn(condition string, params ...interface{}) *Query { - if q.joinAppendOn == nil { - q.err(errors.New("pg: no joins to apply JoinOn")) - return q - } - q.joinAppendOn(&condAppender{ - sep: " AND ", - cond: condition, - params: params, - }) - return q -} - -func (q *Query) JoinOnOr(condition string, params ...interface{}) *Query { - if q.joinAppendOn == nil { - q.err(errors.New("pg: no joins to apply JoinOn")) - return q - } - q.joinAppendOn(&condAppender{ - sep: " OR ", - cond: condition, - params: params, - }) - return q -} - -func (q *Query) Group(columns ...string) *Query { - for _, column := range columns { - q.group = append(q.group, fieldAppender{column}) - } - return q -} - -func (q *Query) GroupExpr(group string, params ...interface{}) *Query { - q.group = append(q.group, &queryParamsAppender{group, params}) - return q -} - -func (q *Query) Having(having string, params ...interface{}) *Query { - q.having = append(q.having, &queryParamsAppender{having, params}) - return q -} - -// Order adds sort order to the Query quoting column name. Does not expand params like ?TableAlias etc. -// OrderExpr can be used to bypass quoting restriction or for params expansion. -func (q *Query) Order(orders ...string) *Query { -loop: - for _, order := range orders { - if order == "" { - continue - } - ind := strings.Index(order, " ") - if ind != -1 { - field := order[:ind] - sort := order[ind+1:] - switch internal.UpperString(sort) { - case "ASC", "DESC", "ASC NULLS FIRST", "DESC NULLS FIRST", - "ASC NULLS LAST", "DESC NULLS LAST": - q = q.OrderExpr("? ?", types.F(field), types.Q(sort)) - continue loop - } - } - - q.order = append(q.order, fieldAppender{order}) - } - return q -} - -// Order adds sort order to the Query. -func (q *Query) OrderExpr(order string, params ...interface{}) *Query { - if order != "" { - q.order = append(q.order, &queryParamsAppender{order, params}) - } - return q -} - -func (q *Query) Limit(n int) *Query { - q.limit = n - return q -} - -func (q *Query) Offset(n int) *Query { - q.offset = n - return q -} - -func (q *Query) OnConflict(s string, params ...interface{}) *Query { - q.onConflict = &queryParamsAppender{s, params} - return q -} - -func (q *Query) onConflictDoUpdate() bool { - return q.onConflict != nil && - strings.HasSuffix(internal.UpperString(q.onConflict.query), "DO UPDATE") -} - -func (q *Query) Returning(s string, params ...interface{}) *Query { - q.returning = append(q.returning, &queryParamsAppender{s, params}) - return q -} - -func (q *Query) For(s string, params ...interface{}) *Query { - q.selFor = &queryParamsAppender{s, params} - return q -} - -// Apply calls the fn passing the Query as an argument. -func (q *Query) Apply(fn func(*Query) (*Query, error)) *Query { - qq, err := fn(q) - if err != nil { - q.err(err) - return q - } - return qq -} - -// Count returns number of rows matching the query using count aggregate function. -func (q *Query) Count() (int, error) { - if q.stickyErr != nil { - return 0, q.stickyErr - } - - var count int - _, err := q.db.QueryOne( - Scan(&count), - q.countSelectQuery("count(*)"), - q.model, - ) - return count, err -} - -func (q *Query) countSelectQuery(column string) selectQuery { - return selectQuery{ - q: q, - count: column, - } -} - -// First sorts rows by primary key and selects the first row. -// It is a shortcut for: -// -// q.OrderExpr("id ASC").Limit(1) -func (q *Query) First() error { - err := q.model.Table().checkPKs() - if err != nil { - return err - } - - b := appendColumns(nil, q.model.Table().Alias, q.model.Table().PKs) - return q.OrderExpr(internal.BytesToString(b)).Limit(1).Select() -} - -// Last sorts rows by primary key and selects the last row. -// It is a shortcut for: -// -// q.OrderExpr("id DESC").Limit(1) -func (q *Query) Last() error { - err := q.model.Table().checkPKs() - if err != nil { - return err - } - - // TODO: fix for multi columns - b := appendColumns(nil, q.model.Table().Alias, q.model.Table().PKs) - b = append(b, " DESC"...) - return q.OrderExpr(internal.BytesToString(b)).Limit(1).Select() -} - -// Select selects the model. -func (q *Query) Select(values ...interface{}) error { - if q.stickyErr != nil { - return q.stickyErr - } - - model, err := q.newModel(values...) - if err != nil { - return err - } - - q, err = model.BeforeSelectQuery(q.db, q) - if err != nil { - return err - } - - res, err := q.query(model, selectQuery{q: q}) - if err != nil { - return err - } - - if res.RowsReturned() > 0 { - if q.model != nil { - if err := q.selectJoins(q.model.GetJoins()); err != nil { - return err - } - } - if err := model.AfterSelect(q.db); err != nil { - return err - } - } - - return nil -} - -func (q *Query) newModel(values ...interface{}) (Model, error) { - if len(values) > 0 { - return NewModel(values...) - } - return q.model, nil -} - -func (q *Query) query(model Model, query interface{}) (Result, error) { - if _, ok := model.(useQueryOne); ok { - return q.db.QueryOne(model, query, q.model) - } - return q.db.Query(model, query, q.model) -} - -// SelectAndCount runs Select and Count in two goroutines, -// waits for them to finish and returns the result. If query limit is -1 -// it does not select any data and only counts the results. -func (q *Query) SelectAndCount(values ...interface{}) (count int, firstErr error) { - if q.stickyErr != nil { - return 0, q.stickyErr - } - - var wg sync.WaitGroup - var mu sync.Mutex - - if q.limit >= 0 { - wg.Add(1) - go func() { - defer wg.Done() - err := q.Select(values...) - if err != nil { - mu.Lock() - if firstErr == nil { - firstErr = err - } - mu.Unlock() - } - }() - } - - wg.Add(1) - go func() { - defer wg.Done() - var err error - count, err = q.Count() - if err != nil { - mu.Lock() - if firstErr == nil { - firstErr = err - } - mu.Unlock() - } - }() - - wg.Wait() - return count, firstErr -} - -// SelectAndCountEstimate runs Select and CountEstimate in two goroutines, -// waits for them to finish and returns the result. If query limit is -1 -// it does not select any data and only counts the results. -func (q *Query) SelectAndCountEstimate(threshold int, values ...interface{}) (count int, firstErr error) { - if q.stickyErr != nil { - return 0, q.stickyErr - } - - var wg sync.WaitGroup - var mu sync.Mutex - - if q.limit >= 0 { - wg.Add(1) - go func() { - defer wg.Done() - err := q.Select(values...) - if err != nil { - mu.Lock() - if firstErr == nil { - firstErr = err - } - mu.Unlock() - } - }() - } - - wg.Add(1) - go func() { - defer wg.Done() - var err error - count, err = q.CountEstimate(threshold) - if err != nil { - mu.Lock() - if firstErr == nil { - firstErr = err - } - mu.Unlock() - } - }() - - wg.Wait() - return count, firstErr -} - -// ForEach calls the function for each row returned by the query -// without loading all rows into the memory. -// Function accepts a struct, pointer to a struct, orm.Model, -// or values for columns in a row. Function must return an error. -func (q *Query) ForEach(fn interface{}) error { - m := newFuncModel(fn) - return q.Select(m) -} - -func (q *Query) forEachHasOneJoin(fn func(*join)) { - if q.model == nil { - return - } - q._forEachHasOneJoin(fn, q.model.GetJoins()) -} - -func (q *Query) _forEachHasOneJoin(fn func(*join), joins []join) { - for i := range joins { - j := &joins[i] - switch j.Rel.Type { - case HasOneRelation, BelongsToRelation: - fn(j) - q._forEachHasOneJoin(fn, j.JoinModel.GetJoins()) - } - } -} - -func (q *Query) selectJoins(joins []join) error { - var err error - for i := range joins { - j := &joins[i] - if j.Rel.Type == HasOneRelation || j.Rel.Type == BelongsToRelation { - err = q.selectJoins(j.JoinModel.GetJoins()) - } else { - err = j.Select(q.New()) - } - if err != nil { - return err - } - } - return nil -} - -// Insert inserts the model. -func (q *Query) Insert(values ...interface{}) (Result, error) { - if q.stickyErr != nil { - return nil, q.stickyErr - } - - model, err := q.newModel(values...) - if err != nil { - return nil, err - } - - if q.model != nil && q.model.Table().HasFlag(BeforeInsertHookFlag) { - err = q.model.BeforeInsert(q.db) - if err != nil { - return nil, err - } - } - - query := &insertQuery{q: q} - res, err := q.returningQuery(model, query) - if err != nil { - return nil, err - } - - if q.model != nil { - err = q.model.AfterInsert(q.db) - if err != nil { - return nil, err - } - } - - return res, nil -} - -// SelectOrInsert selects the model inserting one if it does not exist. -// It returns true when model was inserted. -func (q *Query) SelectOrInsert(values ...interface{}) (inserted bool, _ error) { - if q.stickyErr != nil { - return false, q.stickyErr - } - - insertq := q - if len(insertq.columns) > 0 { - insertq = insertq.Copy() - insertq.columns = nil - } - - var insertErr error - for i := 0; i < 5; i++ { - if i >= 2 { - time.Sleep(internal.RetryBackoff(i-2, 250*time.Millisecond, 5*time.Second)) - } - - err := q.Select(values...) - if err == nil { - return false, nil - } - if err != internal.ErrNoRows { - return false, err - } - - res, err := insertq.Insert(values...) - if err != nil { - insertErr = err - if err == internal.ErrNoRows { - continue - } - if pgErr, ok := err.(internal.PGError); ok { - if pgErr.IntegrityViolation() { - continue - } - if pgErr.Field('C') == "55000" { - // Retry on "#55000 attempted to delete invisible tuple". - continue - } - } - return false, err - } - if res.RowsAffected() == 1 { - return true, nil - } - } - - err := fmt.Errorf( - "pg: SelectOrInsert: select returns no rows (insert fails with err=%q)", - insertErr, - ) - return false, err -} - -// Update updates the model. -func (q *Query) Update(scan ...interface{}) (Result, error) { - return q.update(scan, false) -} - -// Update updates the model omitting null columns. -func (q *Query) UpdateNotNull(scan ...interface{}) (Result, error) { - return q.update(scan, true) -} - -func (q *Query) update(scan []interface{}, omitZero bool) (Result, error) { - if q.stickyErr != nil { - return nil, q.stickyErr - } - - model, err := q.newModel(scan...) - if err != nil { - return nil, err - } - - if q.model != nil { - err = q.model.BeforeUpdate(q.db) - if err != nil { - return nil, err - } - } - - query := updateQuery{q: q, omitZero: omitZero} - res, err := q.returningQuery(model, query) - if err != nil { - return nil, err - } - - if q.model != nil { - err = q.model.AfterUpdate(q.db) - if err != nil { - return nil, err - } - } - - return res, nil -} - -func (q *Query) returningQuery(model Model, query interface{}) (Result, error) { - if len(q.returning) == 0 { - return q.db.Query(model, query, q.model) - } - if _, ok := model.(useQueryOne); ok { - return q.db.QueryOne(model, query, q.model) - } - return q.db.Query(model, query, q.model) -} - -// Delete deletes the model. When model has deleted_at column the row -// is soft deleted instead. -func (q *Query) Delete(values ...interface{}) (Result, error) { - if q.softDelete() { - q.model.setDeletedAt() - columns := q.columns - q.columns = nil - res, err := q.Column("deleted_at").Update(values...) - q.columns = columns - return res, err - } - return q.ForceDelete(values...) -} - -// Delete forces delete of the model with deleted_at column. -func (q *Query) ForceDelete(values ...interface{}) (Result, error) { - if q.stickyErr != nil { - return nil, q.stickyErr - } - if q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - q.deleted = true - - model, err := q.newModel(values...) - if err != nil { - return nil, err - } - - if q.model != nil { - err = q.model.BeforeDelete(q.db) - if err != nil { - return nil, err - } - } - - res, err := q.returningQuery(model, deleteQuery{q}) - if err != nil { - return nil, err - } - - if q.model != nil { - err = q.model.AfterDelete(q.db) - if err != nil { - return nil, err - } - } - - return res, nil -} - -// Exec is an alias for DB.Exec. -func (q *Query) Exec(query interface{}, params ...interface{}) (Result, error) { - params = append(params, q.model) - return q.db.Exec(query, params...) -} - -// ExecOne is an alias for DB.ExecOne. -func (q *Query) ExecOne(query interface{}, params ...interface{}) (Result, error) { - params = append(params, q.model) - return q.db.ExecOne(query, params...) -} - -// Query is an alias for DB.Query. -func (q *Query) Query(model, query interface{}, params ...interface{}) (Result, error) { - params = append(params, q.model) - return q.db.Query(model, query, params...) -} - -// QueryOne is an alias for DB.QueryOne. -func (q *Query) QueryOne(model, query interface{}, params ...interface{}) (Result, error) { - params = append(params, q.model) - return q.db.QueryOne(model, query, params...) -} - -// CopyFrom is an alias from DB.CopyFrom. -func (q *Query) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error) { - params = append(params, q.model) - return q.db.CopyFrom(r, query, params...) -} - -// CopyTo is an alias from DB.CopyTo. -func (q *Query) CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error) { - params = append(params, q.model) - return q.db.CopyTo(w, query, params...) -} - -func (q *Query) FormatQuery(b []byte, query string, params ...interface{}) []byte { - params = append(params, q.model) - if q.db != nil { - return q.db.FormatQuery(b, query, params...) - } - return formatter.Append(b, query, params...) -} - -// Exists returns true or false depending if there are any rows matching the query. -func (q *Query) Exists() (bool, error) { - cp := q.Copy() // copy to not change original query - cp.columns = []FormatAppender{fieldAppender{"1"}} - cp.order = nil - cp.limit = 1 - res, err := q.db.Exec(selectQuery{q: q}) - if err != nil { - return false, err - } - return res.RowsAffected() > 0, nil -} - -func (q *Query) hasModel() bool { - return !q.ignoreModel && q.model != nil -} - -func (q *Query) hasTables() bool { - return q.hasModel() || len(q.tables) > 0 -} - -func (q *Query) appendTableName(b []byte) []byte { - return q.FormatQuery(b, string(q.model.Table().Name)) -} - -func (q *Query) appendTableNameWithAlias(b []byte) []byte { - b = q.appendTableName(b) - b = append(b, " AS "...) - b = append(b, q.model.Table().Alias...) - return b -} - -func (q *Query) appendFirstTable(b []byte) []byte { - if q.hasModel() { - return q.appendTableName(b) - } - if len(q.tables) > 0 { - b = q.tables[0].AppendFormat(b, q) - } - return b -} - -func (q *Query) appendFirstTableWithAlias(b []byte) []byte { - if q.hasModel() { - return q.appendTableNameWithAlias(b) - } - if len(q.tables) > 0 { - b = q.tables[0].AppendFormat(b, q) - } - return b -} - -func (q *Query) hasMultiTables() bool { - if q.hasModel() { - return len(q.tables) > 0 - } - return len(q.tables) > 1 -} - -func (q *Query) appendOtherTables(b []byte) []byte { - tables := q.tables - if !q.hasModel() { - tables = tables[1:] - } - for i, f := range tables { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q) - } - return b -} - -func (q *Query) appendColumns(b []byte) []byte { - for i, f := range q.columns { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q) - } - return b -} - -func (q *Query) hasWhere() bool { - return len(q.where) > 0 || q.softDelete() -} - -func (q *Query) mustAppendWhere(b []byte) ([]byte, error) { - if q.hasWhere() { - b = q.appendWhere(b) - return b, nil - } - - if q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - err := errors.New( - "pg: Update and Delete queries require Where clause (try WherePK)") - return nil, err -} - -func (q *Query) appendWhere(b []byte) []byte { - b = q._appendWhere(b, q.where) - if q.softDelete() { - if len(q.where) > 0 { - b = append(b, " AND "...) - } - b = append(b, q.model.Table().Alias...) - b = q.appendSoftDelete(b) - } - return b -} - -func (q *Query) appendSoftDelete(b []byte) []byte { - if q.deleted { - b = append(b, ".deleted_at IS NOT NULL"...) - } else { - b = append(b, ".deleted_at IS NULL"...) - } - return b -} - -func (q *Query) appendUpdWhere(b []byte) []byte { - return q._appendWhere(b, q.updWhere) -} - -func (q *Query) _appendWhere(b []byte, where []sepFormatAppender) []byte { - for i, f := range where { - if i > 0 { - b = f.AppendSep(b) - } - b = f.AppendFormat(b, q) - } - return b -} - -func (q *Query) appendSet(b []byte) []byte { - b = append(b, " SET "...) - for i, f := range q.set { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q) - } - return b -} - -func (q *Query) appendReturning(b []byte) []byte { - b = append(b, " RETURNING "...) - for i, f := range q.returning { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q) - } - return b -} - -func (q *Query) appendWith(b []byte) ([]byte, error) { - var err error - b = append(b, "WITH "...) - for i, with := range q.with { - if i > 0 { - b = append(b, ", "...) - } - b = types.AppendField(b, with.name, 1) - b = append(b, " AS ("...) - - b, err = selectQuery{q: with.query}.AppendQuery(b) - if err != nil { - return nil, err - } - - b = append(b, ')') - } - b = append(b, ' ') - return b, nil -} - -func (q *Query) isSliceModel() bool { - if !q.hasModel() { - return false - } - return q.model.Kind() == reflect.Slice && q.model.Value().Len() > 0 -} - -//------------------------------------------------------------------------------ - -type wherePKQuery struct { - *Query -} - -func (wherePKQuery) AppendSep(b []byte) []byte { - return append(b, " AND "...) -} - -func (q wherePKQuery) AppendFormat(b []byte, f QueryFormatter) []byte { - table := q.model.Table() - value := q.model.Value() - return appendColumnAndValue(b, value, table.Alias, table.PKs) -} - -func appendColumnAndValue(b []byte, v reflect.Value, alias types.Q, fields []*Field) []byte { - for i, f := range fields { - if i > 0 { - b = append(b, " AND "...) - } - b = append(b, alias...) - b = append(b, '.') - b = append(b, f.Column...) - b = append(b, " = "...) - b = f.AppendValue(b, v, 1) - } - return b -} - -func appendColumnAndSliceValue(b []byte, slice reflect.Value, alias types.Q, fields []*Field) []byte { - if slice.Len() == 0 { - return append(b, "1 = 2"...) - } - - if len(fields) > 1 { - b = append(b, '(') - } - b = appendColumns(b, alias, fields) - if len(fields) > 1 { - b = append(b, ')') - } - - b = append(b, " IN ("...) - - for i := 0; i < slice.Len(); i++ { - if i > 0 { - b = append(b, ", "...) - } - - el := indirect(slice.Index(i)) - - if len(fields) > 1 { - b = append(b, '(') - } - for i, f := range fields { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendValue(b, el, 1) - } - if len(fields) > 1 { - b = append(b, ')') - } - } - b = append(b, ')') - - return b -} diff --git a/vendor/github.com/go-pg/pg/orm/select.go b/vendor/github.com/go-pg/pg/orm/select.go deleted file mode 100644 index faa15e3f2..000000000 --- a/vendor/github.com/go-pg/pg/orm/select.go +++ /dev/null @@ -1,201 +0,0 @@ -package orm - -import ( - "strconv" - "strings" -) - -func Select(db DB, model interface{}) error { - return NewQuery(db, model).WherePK().Select() -} - -type selectQuery struct { - q *Query - - count string -} - -var _ QueryAppender = (*selectQuery)(nil) - -func (q selectQuery) Copy() QueryAppender { - return selectQuery{ - q: q.q.Copy(), - count: q.count, - } -} - -func (q selectQuery) Query() *Query { - return q.q -} - -func (q selectQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - - var err error - - cteCount := q.count != "" && (len(q.q.group) > 0 || q.isDistinct()) - if cteCount { - b = append(b, `WITH "_count_wrapper" AS (`...) - } - - if len(q.q.with) > 0 { - b, err = q.q.appendWith(b) - if err != nil { - return nil, err - } - } - - b = append(b, "SELECT "...) - if q.count != "" && !cteCount { - b = append(b, q.count...) - } else { - b = q.appendColumns(b) - } - - if q.q.hasTables() { - b = append(b, " FROM "...) - b = q.appendTables(b) - } - - q.q.forEachHasOneJoin(func(j *join) { - b = append(b, ' ') - b = j.appendHasOneJoin(q.q, b) - }) - if len(q.q.joins) > 0 { - for _, j := range q.q.joins { - b = append(b, ' ') - b = j.join.AppendFormat(b, q.q) - if len(j.on) > 0 { - b = append(b, " ON "...) - } - for i, on := range j.on { - if i > 0 { - b = on.AppendSep(b) - } - b = on.AppendFormat(b, q.q) - } - } - } - - if q.q.hasWhere() { - b = append(b, " WHERE "...) - b = q.q.appendWhere(b) - } - - if len(q.q.group) > 0 { - b = append(b, " GROUP BY "...) - for i, f := range q.q.group { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q.q) - } - } - - if len(q.q.having) > 0 { - b = append(b, " HAVING "...) - for i, f := range q.q.having { - if i > 0 { - b = append(b, " AND "...) - } - b = append(b, '(') - b = f.AppendFormat(b, q.q) - b = append(b, ')') - } - } - - if q.count == "" { - if len(q.q.order) > 0 { - b = append(b, " ORDER BY "...) - for i, f := range q.q.order { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q.q) - } - } - - if q.q.limit != 0 { - b = append(b, " LIMIT "...) - b = strconv.AppendInt(b, int64(q.q.limit), 10) - } - - if q.q.offset != 0 { - b = append(b, " OFFSET "...) - b = strconv.AppendInt(b, int64(q.q.offset), 10) - } - - if q.q.selFor != nil { - b = append(b, " FOR "...) - b = q.q.selFor.AppendFormat(b, q.q) - } - } else if cteCount { - b = append(b, `) SELECT `...) - b = append(b, q.count...) - b = append(b, ` FROM "_count_wrapper"`...) - } - - return b, nil -} - -func (q selectQuery) appendColumns(b []byte) []byte { - start := len(b) - - if q.q.columns != nil { - b = q.q.appendColumns(b) - } else if q.q.hasModel() { - table := q.q.model.Table() - b = appendColumns(b, table.Alias, table.Fields) - } else { - b = append(b, '*') - } - - q.q.forEachHasOneJoin(func(j *join) { - if len(b) != start { - b = append(b, ", "...) - start = len(b) - } - - b = j.appendHasOneColumns(b) - - if len(b) == start { - b = b[:len(b)-2] - } - }) - - return b -} - -func (q selectQuery) isDistinct() bool { - for _, column := range q.q.columns { - column, ok := column.(*queryParamsAppender) - if ok { - if strings.Contains(column.query, "DISTINCT") || - strings.Contains(column.query, "distinct") { - return true - } - } - } - return false -} - -func (q selectQuery) appendTables(b []byte) []byte { - if q.q.hasModel() { - b = q.q.FormatQuery(b, string(q.q.model.Table().NameForSelects)) - b = append(b, " AS "...) - b = append(b, q.q.model.Table().Alias...) - - if len(q.q.tables) > 0 { - b = append(b, ", "...) - } - } - for i, f := range q.q.tables { - if i > 0 { - b = append(b, ", "...) - } - b = f.AppendFormat(b, q.q) - } - return b -} diff --git a/vendor/github.com/go-pg/pg/orm/table.go b/vendor/github.com/go-pg/pg/orm/table.go deleted file mode 100644 index cef782509..000000000 --- a/vendor/github.com/go-pg/pg/orm/table.go +++ /dev/null @@ -1,891 +0,0 @@ -package orm - -import ( - "bytes" - "database/sql" - "encoding/json" - "fmt" - "net" - "reflect" - "strings" - "time" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/types" -) - -const ( - AfterQueryHookFlag = uint16(1) << iota - BeforeSelectQueryHookFlag - AfterSelectHookFlag - BeforeInsertHookFlag - AfterInsertHookFlag - BeforeUpdateHookFlag - AfterUpdateHookFlag - BeforeDeleteHookFlag - AfterDeleteHookFlag - discardUnknownColumns - softDelete -) - -var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() -var ipType = reflect.TypeOf((*net.IP)(nil)).Elem() -var ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem() -var scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem() -var nullBoolType = reflect.TypeOf((*sql.NullBool)(nil)).Elem() -var nullFloatType = reflect.TypeOf((*sql.NullFloat64)(nil)).Elem() -var nullIntType = reflect.TypeOf((*sql.NullInt64)(nil)).Elem() -var nullStringType = reflect.TypeOf((*sql.NullString)(nil)).Elem() - -// Table represents a SQL table created from Go struct. -type Table struct { - Type reflect.Type - zeroStruct reflect.Value - - TypeName string - Name types.Q - NameForSelects types.Q - Alias types.Q - ModelName string - - allFields []*Field // read only - skippedFields []*Field - - Fields []*Field // PKs + DataFields - PKs []*Field - DataFields []*Field - FieldsMap map[string]*Field - - Methods map[string]*Method - Relations map[string]*Relation - Unique map[string][]*Field - - flags uint16 -} - -func (t *Table) setName(name types.Q) { - t.Name = name - t.NameForSelects = name -} - -func newTable(typ reflect.Type) *Table { - t := new(Table) - t.Type = typ - t.zeroStruct = reflect.New(t.Type).Elem() - t.TypeName = internal.ToExported(t.Type.Name()) - t.ModelName = internal.Underscore(t.Type.Name()) - tableName := quoteTableName(tableNameInflector(t.ModelName)) - t.setName(types.Q(types.AppendField(nil, tableName, 1))) - t.Alias = types.Q(types.AppendField(nil, t.ModelName, 1)) - - typ = reflect.PtrTo(t.Type) - if typ.Implements(afterQueryHookType) { - t.SetFlag(AfterQueryHookFlag) - } - if typ.Implements(beforeSelectQueryHookType) { - t.SetFlag(BeforeSelectQueryHookFlag) - } - if typ.Implements(afterSelectHookType) { - t.SetFlag(AfterSelectHookFlag) - } - if typ.Implements(beforeInsertHookType) { - t.SetFlag(BeforeInsertHookFlag) - } - if typ.Implements(afterInsertHookType) { - t.SetFlag(AfterInsertHookFlag) - } - if typ.Implements(beforeUpdateHookType) { - t.SetFlag(BeforeUpdateHookFlag) - } - if typ.Implements(afterUpdateHookType) { - t.SetFlag(AfterUpdateHookFlag) - } - if typ.Implements(beforeDeleteHookType) { - t.SetFlag(BeforeDeleteHookFlag) - } - if typ.Implements(afterDeleteHookType) { - t.SetFlag(AfterDeleteHookFlag) - } - - t.initFields() - t.initMethods() - - return t -} - -func (t *Table) String() string { - return "model=" + t.TypeName -} - -func (t *Table) SetFlag(flag uint16) { - t.flags |= flag -} - -func (t *Table) HasFlag(flag uint16) bool { - if t == nil { - return false - } - return t.flags&flag != 0 -} - -func (t *Table) HasField(field string) bool { - _, err := t.GetField(field) - return err == nil -} - -func (t *Table) checkPKs() error { - if len(t.PKs) == 0 { - return fmt.Errorf("pg: %s does not have primary keys", t) - } - return nil -} - -func (t *Table) mustSoftDelete() error { - if !t.HasFlag(softDelete) { - return fmt.Errorf("pg: %s does not support soft deletes", t) - } - return nil -} - -func (t *Table) AddField(field *Field) { - t.allFields = append(t.allFields, field) - t.Fields = append(t.Fields, field) - if field.HasFlag(PrimaryKeyFlag) { - t.PKs = append(t.PKs, field) - } else { - t.DataFields = append(t.DataFields, field) - } - t.FieldsMap[field.SQLName] = field -} - -func (t *Table) RemoveField(field *Field) { - t.Fields = removeField(t.Fields, field) - if field.HasFlag(PrimaryKeyFlag) { - t.PKs = removeField(t.PKs, field) - } else { - t.DataFields = removeField(t.DataFields, field) - } - delete(t.FieldsMap, field.SQLName) -} - -func removeField(fields []*Field, field *Field) []*Field { - for i, f := range fields { - if f == field { - fields = append(fields[:i], fields[i+1:]...) - } - } - return fields -} - -func (t *Table) GetField(fieldName string) (*Field, error) { - field, ok := t.FieldsMap[fieldName] - if !ok { - return nil, fmt.Errorf("can't find column=%s in %s", fieldName, t) - } - return field, nil -} - -func (t *Table) AppendParam(b []byte, strct reflect.Value, name string) ([]byte, bool) { - field, ok := t.FieldsMap[name] - if ok { - b = field.AppendValue(b, strct, 1) - return b, true - } - - method, ok := t.Methods[name] - if ok { - b = method.AppendValue(b, strct.Addr(), 1) - return b, true - } - - return b, false -} - -func (t *Table) initFields() { - t.Fields = make([]*Field, 0, t.Type.NumField()) - t.FieldsMap = make(map[string]*Field, t.Type.NumField()) - t.addFields(t.Type, nil) -} - -func (t *Table) addFields(typ reflect.Type, baseIndex []int) { - for i := 0; i < typ.NumField(); i++ { - f := typ.Field(i) - - // Make a copy so slice is not shared between fields. - index := make([]int, len(baseIndex)) - copy(index, baseIndex) - - if f.Anonymous { - sqlTag := f.Tag.Get("sql") - if sqlTag == "-" { - continue - } - - fieldType := indirectType(f.Type) - t.addFields(fieldType, append(index, f.Index...)) - - pgTag := parseTag(f.Tag.Get("pg")) - _, inherit := pgTag.Options["inherit"] - _, override := pgTag.Options["override"] - if inherit || override { - embeddedTable := newTable(fieldType) - t.TypeName = embeddedTable.TypeName - t.Name = embeddedTable.Name - t.NameForSelects = embeddedTable.NameForSelects - t.Alias = embeddedTable.Alias - t.ModelName = embeddedTable.ModelName - } - - continue - } - - field := t.newField(f, index) - if field != nil { - t.AddField(field) - } - } -} - -func (t *Table) newField(f reflect.StructField, index []int) *Field { - sqlTag := parseTag(f.Tag.Get("sql")) - - switch f.Name { - case "tableName", "TableName": - if len(index) > 0 { - return nil - } - - if sqlTag.Name != "" { - s, _ := unquoteTagValue(sqlTag.Name) - t.setName(types.Q(quoteTableName(s))) - } - - if v, ok := sqlTag.Options["select"]; ok { - v, _ = unquoteTagValue(v) - t.NameForSelects = types.Q(quoteTableName(v)) - } - - if v, ok := sqlTag.Options["alias"]; ok { - v, _ = unquoteTagValue(v) - t.Alias = types.Q(quoteTableName(v)) - } - - pgTag := parseTag(f.Tag.Get("pg")) - if _, ok := pgTag.Options["discard_unknown_columns"]; ok { - t.SetFlag(discardUnknownColumns) - } - - return nil - } - - if f.PkgPath != "" { - return nil - } - - skip := sqlTag.Name == "-" - if skip || sqlTag.Name == "" { - sqlTag.Name = internal.Underscore(f.Name) - } - - index = append(index, f.Index...) - if field, ok := t.FieldsMap[sqlTag.Name]; ok { - if indexEqual(field.Index, index) { - return field - } - t.RemoveField(field) - } - - field := &Field{ - Field: f, - Type: indirectType(f.Type), - - GoName: f.Name, - SQLName: sqlTag.Name, - Column: types.Q(types.AppendField(nil, sqlTag.Name, 1)), - - Index: index, - } - - if _, ok := sqlTag.Options["notnull"]; ok { - field.SetFlag(NotNullFlag) - } - if v, ok := sqlTag.Options["unique"]; ok { - if v == "" { - field.SetFlag(UniqueFlag) - } else { - if t.Unique == nil { - t.Unique = make(map[string][]*Field) - } - t.Unique[v] = append(t.Unique[v], field) - } - } - if v, ok := sqlTag.Options["default"]; ok { - v, ok = unquoteTagValue(v) - if ok { - field.Default = types.Q(types.AppendString(nil, v, 1)) - } else { - field.Default = types.Q(v) - } - } - - if _, ok := sqlTag.Options["pk"]; ok { - field.SetFlag(PrimaryKeyFlag) - } else if strings.HasSuffix(field.SQLName, "_id") || - strings.HasSuffix(field.SQLName, "_uuid") { - field.SetFlag(ForeignKeyFlag) - } else if strings.HasPrefix(field.SQLName, "fk_") { - field.SetFlag(ForeignKeyFlag) - } else if len(t.PKs) == 0 { - if field.SQLName == "id" || - field.SQLName == "uuid" || - field.SQLName == "pk_"+t.ModelName { - field.SetFlag(PrimaryKeyFlag) - } - } - - pgTag := parseTag(f.Tag.Get("pg")) - - if _, ok := sqlTag.Options["array"]; ok { - field.SetFlag(ArrayFlag) - } else if _, ok := pgTag.Options["array"]; ok { - field.SetFlag(ArrayFlag) - } - - field.SQLType = fieldSQLType(field, pgTag, sqlTag) - if strings.HasSuffix(field.SQLType, "[]") { - field.SetFlag(ArrayFlag) - } - - if v, ok := sqlTag.Options["on_delete"]; ok { - field.OnDelete = v - } - - if v, ok := sqlTag.Options["composite"]; ok { - field.SQLType = v - field.append = compositeAppender(f.Type) - field.scan = compositeScanner(f.Type) - } else if _, ok := pgTag.Options["json_use_number"]; ok { - field.append = types.Appender(f.Type) - field.scan = scanJSONValue - } else if field.HasFlag(ArrayFlag) { - field.append = types.ArrayAppender(f.Type) - field.scan = types.ArrayScanner(f.Type) - } else if _, ok := sqlTag.Options["hstore"]; ok { - field.append = types.HstoreAppender(f.Type) - field.scan = types.HstoreScanner(f.Type) - } else if _, ok := pgTag.Options["hstore"]; ok { - field.append = types.HstoreAppender(f.Type) - field.scan = types.HstoreScanner(f.Type) - } else { - field.append = types.Appender(f.Type) - field.scan = types.Scanner(f.Type) - } - field.isZero = isZeroFunc(f.Type) - - if skip { - t.skippedFields = append(t.skippedFields, field) - t.FieldsMap[field.SQLName] = field - return nil - } - - switch field.SQLName { - case "deleted_at": - if _, ok := pgTag.Options["soft_delete"]; ok && field.Type == timeType { - t.SetFlag(softDelete) - } - } - - return field -} - -func (t *Table) initMethods() { - t.Methods = make(map[string]*Method) - typ := reflect.PtrTo(t.Type) - for i := 0; i < typ.NumMethod(); i++ { - m := typ.Method(i) - if m.PkgPath != "" { - continue - } - if m.Type.NumIn() > 1 { - continue - } - if m.Type.NumOut() != 1 { - continue - } - - retType := m.Type.Out(0) - t.Methods[m.Name] = &Method{ - Index: m.Index, - - appender: types.Appender(retType), - } - } -} - -func (t *Table) init() { - t.initRelations() - t.initInlines() -} - -func (t *Table) initRelations() { - for i := 0; i < len(t.Fields); { - f := t.Fields[i] - if t.tryRelation(f) { - t.Fields = removeField(t.Fields, f) - t.DataFields = removeField(t.DataFields, f) - } else { - i++ - } - } -} - -func (t *Table) initInlines() { - for _, f := range t.skippedFields { - if f.Type.Kind() == reflect.Struct { - joinTable := _tables.get(f.Type, true) - t.inlineFields(f, joinTable.allFields) - } - } -} - -func (t *Table) tryRelation(field *Field) bool { - if isColumn(field.Type) { - return false - } - - switch field.Type.Kind() { - case reflect.Slice: - return t.tryRelationSlice(field) - case reflect.Struct: - return t.tryRelationStruct(field) - } - return false -} - -func (t *Table) tryRelationSlice(field *Field) bool { - elemType := indirectType(field.Type.Elem()) - if elemType.Kind() != reflect.Struct { - return false - } - - pgTag := parseTag(field.Field.Tag.Get("pg")) - joinTable := _tables.get(elemType, true) - - fk, fkOK := pgTag.Options["fk"] - if fkOK { - if fk == "-" { - return false - } - fk = tryUnderscorePrefix(fk) - } - - if m2mTableName, _ := pgTag.Options["many2many"]; m2mTableName != "" { - m2mTable := _tables.getByName(m2mTableName) - - var m2mTableAlias types.Q - if m2mTable != nil { - m2mTableAlias = m2mTable.Alias - } else if ind := strings.IndexByte(m2mTableName, '.'); ind >= 0 { - m2mTableAlias = types.Q(m2mTableName[ind+1:]) - } else { - m2mTableAlias = types.Q(m2mTableName) - } - - var fks []string - if !fkOK { - fk = t.ModelName + "_" - } - if m2mTable != nil { - keys := foreignKeys(t, m2mTable, fk, fkOK) - if len(keys) == 0 { - return false - } - for _, fk := range keys { - fks = append(fks, fk.SQLName) - } - } else { - if fkOK && len(t.PKs) == 1 { - fks = append(fks, fk) - } else { - for _, pk := range t.PKs { - fks = append(fks, fk+pk.SQLName) - } - } - } - - joinFK, joinFKOK := pgTag.Options["joinFK"] - if joinFKOK { - joinFK = tryUnderscorePrefix(joinFK) - } else { - joinFK = joinTable.ModelName + "_" - } - var joinFKs []string - if m2mTable != nil { - keys := foreignKeys(joinTable, m2mTable, joinFK, joinFKOK) - if len(keys) == 0 { - return false - } - for _, fk := range keys { - joinFKs = append(joinFKs, fk.SQLName) - } - } else { - if joinFKOK && len(joinTable.PKs) == 1 { - joinFKs = append(joinFKs, joinFK) - } else { - for _, pk := range joinTable.PKs { - joinFKs = append(joinFKs, joinFK+pk.SQLName) - } - } - } - - t.addRelation(&Relation{ - Type: Many2ManyRelation, - Field: field, - JoinTable: joinTable, - M2MTableName: types.Q(m2mTableName), - M2MTableAlias: m2mTableAlias, - BaseFKs: fks, - JoinFKs: joinFKs, - }) - return true - } - - s, polymorphic := pgTag.Options["polymorphic"] - var typeField *Field - if polymorphic { - fk = tryUnderscorePrefix(s) - - typeField = joinTable.getField(fk + "type") - if typeField == nil { - return false - } - } else if !fkOK { - fk = t.ModelName + "_" - } - - fks := foreignKeys(t, joinTable, fk, fkOK || polymorphic) - if len(fks) == 0 { - return false - } - - var fkValues []*Field - fkValue, ok := pgTag.Options["fk_value"] - if ok { - if len(fks) > 1 { - panic(fmt.Errorf("got fk_value, but there are %d fks", len(fks))) - } - - f := t.getField(fkValue) - if f == nil { - panic(fmt.Errorf("fk_value=%q not found in %s", fkValue, t)) - } - fkValues = append(fkValues, f) - } else { - fkValues = t.PKs - } - - if len(fks) > 0 { - t.addRelation(&Relation{ - Type: HasManyRelation, - Field: field, - JoinTable: joinTable, - FKs: fks, - Polymorphic: typeField, - FKValues: fkValues, - }) - return true - } - - return false -} - -func (t *Table) tryRelationStruct(field *Field) bool { - pgTag := parseTag(field.Field.Tag.Get("pg")) - joinTable := _tables.get(field.Type, true) - if len(joinTable.allFields) == 0 { - return false - } - - res := t.tryHasOne(joinTable, field, pgTag) || - t.tryBelongsToOne(joinTable, field, pgTag) - t.inlineFields(field, joinTable.allFields) - return res -} - -func (t *Table) inlineFields(strct *Field, structFields []*Field) { - for _, f := range structFields { - f = f.Copy() - f.GoName = strct.GoName + "_" + f.GoName - f.SQLName = strct.SQLName + "__" + f.SQLName - f.Column = types.Q(types.AppendField(nil, f.SQLName, 1)) - f.Index = appendNew(strct.Index, f.Index...) - if _, ok := t.FieldsMap[f.SQLName]; !ok { - t.FieldsMap[f.SQLName] = f - } - } -} - -func appendNew(dst []int, src ...int) []int { - cp := make([]int, len(dst)+len(src)) - copy(cp, dst) - copy(cp[len(dst):], src) - return cp -} - -func isPostgresKeyword(s string) bool { - switch strings.ToLower(s) { - case "user", "group", "constraint", "limit", - "member", "placing", "references", "table": - return true - default: - return false - } -} - -func isColumn(typ reflect.Type) bool { - return typ.Implements(scannerType) || reflect.PtrTo(typ).Implements(scannerType) -} - -func fieldSQLType(field *Field, pgTag, sqlTag *tag) string { - if typ, ok := sqlTag.Options["type"]; ok { - field.SetFlag(customTypeFlag) - typ, _ = unquoteTagValue(typ) - return typ - } - - if _, ok := sqlTag.Options["hstore"]; ok { - field.SetFlag(customTypeFlag) - return "hstore" - } else if _, ok := pgTag.Options["hstore"]; ok { - field.SetFlag(customTypeFlag) - return "hstore" - } - - if field.HasFlag(ArrayFlag) { - sqlType := sqlType(field.Type.Elem()) - return sqlType + "[]" - } - - sqlType := sqlType(field.Type) - if field.HasFlag(PrimaryKeyFlag) { - return pkSQLType(sqlType) - } - - switch sqlType { - case "timestamptz": - field.SetFlag(customTypeFlag) - } - - return sqlType -} - -func sqlType(typ reflect.Type) string { - switch typ { - case timeType: - return "timestamptz" - case ipType: - return "inet" - case ipNetType: - return "cidr" - case nullBoolType: - return "boolean" - case nullFloatType: - return "double precision" - case nullIntType: - return "bigint" - case nullStringType: - return "text" - } - - switch typ.Kind() { - case reflect.Int8, reflect.Uint8, reflect.Int16: - return "smallint" - case reflect.Uint16, reflect.Int32: - return "integer" - case reflect.Uint32, reflect.Int64, reflect.Int: - return "bigint" - case reflect.Uint, reflect.Uint64: - // The lesser of two evils. - return "bigint" - case reflect.Float32: - return "real" - case reflect.Float64: - return "double precision" - case reflect.Bool: - return "boolean" - case reflect.String: - return "text" - case reflect.Map, reflect.Struct: - return "jsonb" - case reflect.Array, reflect.Slice: - if typ.Elem().Kind() == reflect.Uint8 { - return "bytea" - } - return "jsonb" - default: - return typ.Kind().String() - } -} - -func pkSQLType(s string) string { - switch s { - case "smallint": - return "smallserial" - case "integer": - return "serial" - case "bigint": - return "bigserial" - } - return s -} - -func sqlTypeEqual(a, b string) bool { - if a == b { - return true - } - return pkSQLType(a) == pkSQLType(b) -} - -func (t *Table) tryHasOne(joinTable *Table, field *Field, tag *tag) bool { - fk, fkOK := tag.Options["fk"] - if fkOK { - if fk == "-" { - return false - } - fk = tryUnderscorePrefix(fk) - } else { - fk = internal.Underscore(field.GoName) + "_" - } - - fks := foreignKeys(joinTable, t, fk, fkOK) - if len(fks) > 0 { - t.addRelation(&Relation{ - Type: HasOneRelation, - Field: field, - FKs: fks, - JoinTable: joinTable, - }) - return true - } - return false -} - -func (t *Table) tryBelongsToOne(joinTable *Table, field *Field, tag *tag) bool { - fk, fkOK := tag.Options["fk"] - if fkOK { - if fk == "-" { - return false - } - fk = tryUnderscorePrefix(fk) - } else { - fk = internal.Underscore(t.TypeName) + "_" - } - - fks := foreignKeys(t, joinTable, fk, fkOK) - if len(fks) > 0 { - t.addRelation(&Relation{ - Type: BelongsToRelation, - Field: field, - FKs: fks, - JoinTable: joinTable, - }) - return true - } - return false -} - -func (t *Table) addRelation(rel *Relation) { - if t.Relations == nil { - t.Relations = make(map[string]*Relation) - } - _, ok := t.Relations[rel.Field.GoName] - if ok { - panic(fmt.Errorf("%s already has %s", t, rel)) - } - t.Relations[rel.Field.GoName] = rel -} - -func foreignKeys(base, join *Table, fk string, tryFK bool) []*Field { - var fks []*Field - - for _, pk := range base.PKs { - fkName := fk + pk.SQLName - f := join.getField(fkName) - if f != nil && sqlTypeEqual(pk.SQLType, f.SQLType) { - fks = append(fks, f) - } - } - if len(fks) > 0 { - return fks - } - - for _, pk := range base.PKs { - if !strings.HasPrefix(pk.SQLName, "pk_") { - continue - } - fkName := "fk_" + pk.SQLName[3:] - f := join.getField(fkName) - if f != nil && sqlTypeEqual(pk.SQLType, f.SQLType) { - fks = append(fks, f) - } - } - if len(fks) > 0 { - return fks - } - - if fk == "" || len(base.PKs) != 1 { - return nil - } - - if tryFK { - f := join.getField(fk) - if f != nil && sqlTypeEqual(base.PKs[0].SQLType, f.SQLType) { - fks = append(fks, f) - return fks - } - } - - for _, suffix := range []string{"id", "uuid"} { - f := join.getField(fk + suffix) - if f != nil && sqlTypeEqual(base.PKs[0].SQLType, f.SQLType) { - fks = append(fks, f) - return fks - } - } - - return nil -} - -func (t *Table) getField(name string) *Field { - return t.FieldsMap[name] -} - -func scanJSONValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(non-pointer %s)", v.Type()) - } - if b == nil { - v.Set(reflect.New(v.Type()).Elem()) - return nil - } - dec := json.NewDecoder(bytes.NewReader(b)) - dec.UseNumber() - return dec.Decode(v.Addr().Interface()) -} - -func tryUnderscorePrefix(s string) string { - if s == "" { - return s - } - if c := s[0]; internal.IsUpper(c) { - return internal.Underscore(s) + "_" - } - return s -} - -func quoteTableName(s string) string { - if isPostgresKeyword(s) { - return `"` + s + `"` - } - return s -} diff --git a/vendor/github.com/go-pg/pg/orm/table_create.go b/vendor/github.com/go-pg/pg/orm/table_create.go deleted file mode 100644 index c3bdda382..000000000 --- a/vendor/github.com/go-pg/pg/orm/table_create.go +++ /dev/null @@ -1,155 +0,0 @@ -package orm - -import ( - "errors" - "strconv" -) - -type CreateTableOptions struct { - Temp bool - IfNotExists bool - Varchar int // replaces PostgreSQL data type `text` with `varchar(n)` - - // FKConstraints causes CreateTable to create foreign key constraints - // for has one relations. ON DELETE hook can be added using tag - // `sql:"on_delete:RESTRICT"` on foreign key field. - FKConstraints bool -} - -func CreateTable(db DB, model interface{}, opt *CreateTableOptions) error { - q := NewQuery(db, model) - _, err := q.db.Exec(createTableQuery{ - q: q, - opt: opt, - }) - return err -} - -type createTableQuery struct { - q *Query - opt *CreateTableOptions -} - -func (q createTableQuery) Copy() QueryAppender { - return q -} - -func (q createTableQuery) Query() *Query { - return q.q -} - -func (q createTableQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - if q.q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - - table := q.q.model.Table() - - b = append(b, "CREATE "...) - if q.opt != nil && q.opt.Temp { - b = append(b, "TEMP "...) - } - b = append(b, "TABLE "...) - if q.opt != nil && q.opt.IfNotExists { - b = append(b, "IF NOT EXISTS "...) - } - b = q.q.appendTableName(b) - b = append(b, " ("...) - - for i, field := range table.Fields { - if i > 0 { - b = append(b, ", "...) - } - - b = append(b, field.Column...) - b = append(b, " "...) - if q.opt != nil && q.opt.Varchar > 0 && - field.SQLType == "text" && !field.HasFlag(customTypeFlag) { - b = append(b, "varchar("...) - b = strconv.AppendInt(b, int64(q.opt.Varchar), 10) - b = append(b, ")"...) - } else { - b = append(b, field.SQLType...) - } - if field.HasFlag(NotNullFlag) { - b = append(b, " NOT NULL"...) - } - if field.HasFlag(UniqueFlag) { - b = append(b, " UNIQUE"...) - } - if field.Default != "" { - b = append(b, " DEFAULT "...) - b = append(b, field.Default...) - } - } - - b = appendPKConstraint(b, table.PKs) - for _, fields := range table.Unique { - b = appendUnique(b, fields) - } - - if q.opt != nil && q.opt.FKConstraints { - for _, rel := range table.Relations { - b = q.appendFKConstraint(b, table, rel) - } - } - - b = append(b, ")"...) - - return b, nil -} - -func appendPKConstraint(b []byte, pks []*Field) []byte { - if len(pks) == 0 { - return b - } - - b = append(b, ", PRIMARY KEY ("...) - b = appendColumns(b, "", pks) - b = append(b, ")"...) - return b -} - -func appendUnique(b []byte, fields []*Field) []byte { - b = append(b, ", UNIQUE ("...) - b = appendColumns(b, "", fields) - b = append(b, ")"...) - return b -} - -func (q createTableQuery) appendFKConstraint(b []byte, table *Table, rel *Relation) []byte { - if rel.Type != HasOneRelation { - return b - } - - b = append(b, ", FOREIGN KEY ("...) - b = appendColumns(b, "", rel.FKs) - b = append(b, ")"...) - - b = append(b, " REFERENCES "...) - b = q.q.FormatQuery(b, string(rel.JoinTable.Name)) - b = append(b, " ("...) - b = appendColumns(b, "", rel.JoinTable.PKs) - b = append(b, ")"...) - - if s := onDelete(rel.FKs); s != "" { - b = append(b, " ON DELETE "...) - b = append(b, s...) - } - - return b -} - -func onDelete(fks []*Field) string { - var onDelete string - for _, f := range fks { - if f.OnDelete != "" { - onDelete = f.OnDelete - break - } - } - return onDelete -} diff --git a/vendor/github.com/go-pg/pg/orm/table_drop.go b/vendor/github.com/go-pg/pg/orm/table_drop.go deleted file mode 100644 index de509fd25..000000000 --- a/vendor/github.com/go-pg/pg/orm/table_drop.go +++ /dev/null @@ -1,50 +0,0 @@ -package orm - -import "errors" - -type DropTableOptions struct { - IfExists bool - Cascade bool -} - -func DropTable(db DB, model interface{}, opt *DropTableOptions) error { - q := NewQuery(db, model) - _, err := q.db.Exec(dropTableQuery{ - q: q, - opt: opt, - }) - return err -} - -type dropTableQuery struct { - q *Query - opt *DropTableOptions -} - -func (q dropTableQuery) Copy() QueryAppender { - return q -} - -func (q dropTableQuery) Query() *Query { - return q.q -} - -func (q dropTableQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - if q.q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - - b = append(b, "DROP TABLE "...) - if q.opt != nil && q.opt.IfExists { - b = append(b, "IF EXISTS "...) - } - b = q.q.appendTableName(b) - if q.opt != nil && q.opt.Cascade { - b = append(b, " CASCADE"...) - } - - return b, nil -} diff --git a/vendor/github.com/go-pg/pg/orm/update.go b/vendor/github.com/go-pg/pg/orm/update.go deleted file mode 100644 index 492262f80..000000000 --- a/vendor/github.com/go-pg/pg/orm/update.go +++ /dev/null @@ -1,257 +0,0 @@ -package orm - -import ( - "errors" - "fmt" - "reflect" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/types" -) - -func Update(db DB, model interface{}) error { - res, err := NewQuery(db, model).WherePK().Update() - if err != nil { - return err - } - return internal.AssertOneRow(res.RowsAffected()) -} - -type updateQuery struct { - q *Query - omitZero bool -} - -var _ QueryAppender = (*updateQuery)(nil) - -func (q updateQuery) Copy() QueryAppender { - return updateQuery{ - q: q.q.Copy(), - } -} - -func (q updateQuery) Query() *Query { - return q.q -} - -func (q updateQuery) AppendQuery(b []byte) ([]byte, error) { - if q.q.stickyErr != nil { - return nil, q.q.stickyErr - } - - var err error - - if len(q.q.with) > 0 { - b, err = q.q.appendWith(b) - if err != nil { - return nil, err - } - } - - b = append(b, "UPDATE "...) - b = q.q.appendFirstTableWithAlias(b) - - b, err = q.mustAppendSet(b) - if err != nil { - return nil, err - } - - isSliceModel := q.q.isSliceModel() - if q.q.hasMultiTables() || isSliceModel { - b = append(b, " FROM "...) - b = q.q.appendOtherTables(b) - - if isSliceModel { - b, err = q.appendSliceModelData(b) - if err != nil { - return nil, err - } - } - } - - b = append(b, " WHERE "...) - if isSliceModel { - table := q.q.model.Table() - b = appendWhereColumnAndColumn(b, table.Alias, table.PKs) - - if q.q.hasWhere() { - b = append(b, " AND "...) - b = q.q.appendWhere(b) - } - } else { - b, err = q.q.mustAppendWhere(b) - if err != nil { - return nil, err - } - } - - if len(q.q.returning) > 0 { - b = q.q.appendReturning(b) - } - - return b, nil -} - -func (q updateQuery) mustAppendSet(b []byte) ([]byte, error) { - if len(q.q.set) > 0 { - b = q.q.appendSet(b) - return b, nil - } - - if q.q.model == nil { - return nil, errors.New("pg: Model(nil)") - } - - b = append(b, " SET "...) - - value := q.q.model.Value() - var err error - if value.Kind() == reflect.Struct { - b, err = q.appendSetStruct(b, value) - } else { - if value.Len() > 0 { - b, err = q.appendSetSlice(b, value) - } else { - err = fmt.Errorf("pg: can't bulk-update empty slice %s", value.Type()) - } - } - if err != nil { - return nil, err - } - - return b, nil -} - -func (q updateQuery) appendSetStruct(b []byte, strct reflect.Value) ([]byte, error) { - fields, err := q.q.getFields() - if err != nil { - return nil, err - } - - if len(fields) == 0 { - fields = q.q.model.Table().DataFields - } - - pos := len(b) - for _, f := range fields { - omitZero := f.OmitZero() && f.IsZero(strct) - if omitZero && q.omitZero { - continue - } - - if len(b) != pos { - b = append(b, ", "...) - pos = len(b) - } - - b = append(b, f.Column...) - b = append(b, " = "...) - - app, ok := q.q.modelValues[f.SQLName] - if ok { - b = app.AppendFormat(b, q.q) - continue - } - - if f.OmitZero() && f.IsZero(strct) { - b = append(b, "NULL"...) - } else { - b = f.AppendValue(b, strct, 1) - } - } - - return b, nil -} - -func (q updateQuery) appendSetSlice(b []byte, slice reflect.Value) ([]byte, error) { - fields, err := q.q.getFields() - if err != nil { - return nil, err - } - - if len(fields) == 0 { - fields = q.q.model.Table().DataFields - } - - for i, f := range fields { - if i > 0 { - b = append(b, ", "...) - } - - b = append(b, f.Column...) - b = append(b, " = "...) - b = append(b, "_data."...) - b = append(b, f.Column...) - } - - return b, nil -} - -func (q updateQuery) appendSliceModelData(b []byte) ([]byte, error) { - columns, err := q.q.getDataFields() - if err != nil { - return nil, err - } - - if len(columns) > 0 { - columns = append(columns, q.q.model.Table().PKs...) - } else { - columns = q.q.model.Table().Fields - } - - return q.appendSliceValues(b, columns, q.q.model.Value()), nil -} - -func (q updateQuery) appendSliceValues(b []byte, fields []*Field, slice reflect.Value) []byte { - b = append(b, "(VALUES ("...) - for i := 0; i < slice.Len(); i++ { - el := indirect(slice.Index(i)) - b = q.appendValues(b, fields, el) - if i != slice.Len()-1 { - b = append(b, "), ("...) - } - } - b = append(b, ")) AS _data("...) - b = appendColumns(b, "", fields) - b = append(b, ")"...) - return b -} - -func (q updateQuery) appendValues(b []byte, fields []*Field, strct reflect.Value) []byte { - for i, f := range fields { - if i > 0 { - b = append(b, ", "...) - } - - app, ok := q.q.modelValues[f.SQLName] - if ok { - b = app.AppendFormat(b, q.q) - continue - } - - if f.OmitZero() && f.IsZero(strct) { - b = append(b, "NULL"...) - } else { - b = f.AppendValue(b, strct, 1) - } - if f.HasFlag(customTypeFlag) { - b = append(b, "::"...) - b = append(b, f.SQLType...) - } - } - return b -} - -func appendWhereColumnAndColumn(b []byte, alias types.Q, fields []*Field) []byte { - for i, f := range fields { - if i > 0 { - b = append(b, " AND "...) - } - b = append(b, alias...) - b = append(b, '.') - b = append(b, f.Column...) - b = append(b, " = _data."...) - b = append(b, f.Column...) - } - return b -} diff --git a/vendor/github.com/go-pg/pg/orm/url_filter.go b/vendor/github.com/go-pg/pg/orm/url_filter.go deleted file mode 100644 index c3da83b47..000000000 --- a/vendor/github.com/go-pg/pg/orm/url_filter.go +++ /dev/null @@ -1,114 +0,0 @@ -package orm - -import ( - "net/url" - "strings" - - "github.com/go-pg/pg/types" -) - -// URLFilter is used with Query.Apply to add WHERE clauses from the URL values: -// - ?foo=bar - Where(`"foo" = 'bar'`) -// - ?foo=hello&foo=world - Where(`"foo" IN ('hello','world')`) -// - ?foo__exclude=bar - Where(`"foo" != 'bar'`) -// - ?foo__ieq=bar - Where(`"foo" ILIKE 'bar'`) -// - ?foo__match=bar - Where(`"foo" SIMILAR TO 'bar'`) -// - ?foo__gt=42 - Where(`"foo" > 42`) -// - ?foo__gte=42 - Where(`"foo" >= 42`) -// - ?foo__lt=42 - Where(`"foo" < 42`) -// - ?foo__lte=42 - Where(`"foo" <= 42`) -type URLFilter struct { - values URLValues - allowed map[string]struct{} -} - -func NewURLFilter(values url.Values) *URLFilter { - return &URLFilter{ - values: URLValues(values), - } -} - -// Values returns URL values. -func (f *URLFilter) Values() URLValues { - return f.values -} - -func (f *URLFilter) Allow(filter string) { - if f.allowed == nil { - f.allowed = make(map[string]struct{}) - } - f.allowed[filter] = struct{}{} -} - -func (f *URLFilter) isAllowed(filter string) bool { - if len(f.allowed) == 0 { - return true - } - _, ok := f.allowed[filter] - return ok -} - -func (f *URLFilter) Filters(q *Query) (*Query, error) { - if f == nil { - return q, nil - } - - for filter, values := range f.values { - if !f.isAllowed(filter) { - continue - } - - var operation string - if i := strings.Index(filter, "__"); i != -1 { - filter, operation = filter[:i], filter[i+2:] - } - - if q.model.Table().HasField(filter) { - q = addOperator(q, filter, operation, values) - } - } - return q, nil -} - -// URLFilters is a shortcut for NewURLFilter(urlValues).Filters. -func URLFilters(urlValues url.Values) func(*Query) (*Query, error) { - return NewURLFilter(urlValues).Filters -} - -func addOperator(q *Query, field, operator string, values []string) *Query { - switch operator { - case "gt": - q = forEachValue(q, field, values, "? > ?") - case "gte": - q = forEachValue(q, field, values, "? >= ?") - case "lt": - q = forEachValue(q, field, values, "? < ?") - case "lte": - q = forEachValue(q, field, values, "? <= ?") - case "ieq": - q = forEachValue(q, field, values, "? ILIKE ?") - case "match": - q = forEachValue(q, field, values, "? SIMILAR TO ?") - case "exclude": - q = forAllValues(q, field, values, "? != ?", "? NOT IN (?)") - case "", "include": - q = forAllValues(q, field, values, "? = ?", "? IN (?)") - } - return q -} - -func forEachValue(q *Query, field string, values []string, queryTemplate string) *Query { - for _, value := range values { - q = q.Where(queryTemplate, types.F(field), value) - } - return q -} - -func forAllValues(q *Query, field string, values []string, queryTemplate, queryArrayTemplate string) *Query { - if len(values) > 1 { - q = q.Where(queryArrayTemplate, types.F(field), types.InSlice(values)) - } else { - q = q.Where(queryTemplate, types.F(field), values[0]) - } - return q -} diff --git a/vendor/github.com/go-pg/pg/orm/url_values.go b/vendor/github.com/go-pg/pg/orm/url_values.go deleted file mode 100644 index 9ba600075..000000000 --- a/vendor/github.com/go-pg/pg/orm/url_values.go +++ /dev/null @@ -1,106 +0,0 @@ -package orm - -import ( - "net/url" - "strconv" - "time" - - "github.com/go-pg/pg/types" -) - -type URLValues map[string][]string - -func (v URLValues) Has(name string) bool { - _, ok := v[name] - return ok -} - -func (v URLValues) SetDefault(name string, values ...string) { - if !v.Has(name) { - v[name] = values - } -} - -func (v URLValues) Strings(name string) []string { - return v[name] -} - -func (v URLValues) String(name string) string { - values := v.Strings(name) - if len(values) == 0 { - return "" - } - return values[0] -} - -func (v URLValues) Bool(name string) (bool, error) { - if !v.Has(name) { - return false, nil - } - s := v.String(name) - if s == "" { - return true, nil - } - return strconv.ParseBool(s) -} - -func (v URLValues) Int(name string) (int, error) { - s := v.String(name) - if s == "" { - return 0, nil - } - return strconv.Atoi(s) -} - -func (v URLValues) MaybeInt(name string) int { - n, _ := v.Int(name) - return n -} - -func (v URLValues) Int64(name string) (int64, error) { - s := v.String(name) - if s == "" { - return 0, nil - } - return strconv.ParseInt(s, 10, 64) -} - -func (v URLValues) MaybeInt64(name string) int64 { - n, _ := v.Int64(name) - return n -} - -func (v URLValues) Time(name string) (time.Time, error) { - s := v.String(name) - if s == "" { - return time.Time{}, nil - } - - n, err := strconv.ParseInt(s, 10, 64) - if err == nil { - return time.Unix(n, 0), nil - } - return types.ParseTimeString(s) -} - -func (v URLValues) MaybeTime(name string) time.Time { - tm, _ := v.Time(name) - return tm -} - -func (v URLValues) Duration(name string) (time.Duration, error) { - s := v.String(name) - if s == "" { - return 0, nil - } - return time.ParseDuration(s) -} - -func (v URLValues) MaybeDuration(name string) time.Duration { - dur, _ := v.Duration(name) - return dur -} - -func (v URLValues) Pager() *Pager { - return NewPager(url.Values(v)) -} diff --git a/vendor/github.com/go-pg/pg/pg.go b/vendor/github.com/go-pg/pg/pg.go deleted file mode 100644 index adae48663..000000000 --- a/vendor/github.com/go-pg/pg/pg.go +++ /dev/null @@ -1,209 +0,0 @@ -package pg - -import ( - "log" - "os" - "strconv" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/orm" - "github.com/go-pg/pg/types" -) - -// Discard is used with Query and QueryOne to discard rows. -var Discard orm.Discard - -func init() { - SetLogger(log.New(os.Stderr, "pg: ", log.LstdFlags|log.Lshortfile)) -} - -// Model returns new query for the optional model. -func Model(model ...interface{}) *orm.Query { - return orm.NewQuery(nil, model...) -} - -// Scan returns ColumnScanner that copies the columns in the -// row into the values. -func Scan(values ...interface{}) orm.ColumnScanner { - return orm.Scan(values...) -} - -// Q replaces any placeholders found in the query. -func Q(query string, params ...interface{}) types.ValueAppender { - return orm.Q(query, params...) -} - -// F quotes a SQL identifier such as a table or column name replacing any -// placeholders found in the field. -func F(field string) types.ValueAppender { - return types.F(field) -} - -// In accepts a slice and returns a wrapper that can be used with PostgreSQL -// IN operator: -// -// Where("id IN (?)", pg.In([]int{1, 2, 3, 4})) -// -// produces -// -// WHERE id IN (1, 2, 3, 4) -func In(slice interface{}) types.ValueAppender { - return types.InSlice(slice) -} - -// InMulti accepts multiple values and returns a wrapper that can be used -// with PostgreSQL IN operator: -// -// Where("(id1, id2) IN (?)", pg.InMulti([]int{1, 2}, []int{3, 4})) -// -// produces -// -// WHERE (id1, id2) IN ((1, 2), (3, 4)) -func InMulti(values ...interface{}) types.ValueAppender { - return types.In(values...) -} - -// Array accepts a slice and returns a wrapper for working with PostgreSQL -// array data type. -// -// For struct fields you can use array tag: -// -// Emails []string `sql:",array"` -func Array(v interface{}) *types.Array { - return types.NewArray(v) -} - -// Hstore accepts a map and returns a wrapper for working with hstore data type. -// Supported map types are: -// - map[string]string -// -// For struct fields you can use hstore tag: -// -// Attrs map[string]string `sql:",hstore"` -func Hstore(v interface{}) *types.Hstore { - return types.NewHstore(v) -} - -func SetLogger(logger *log.Logger) { - internal.Logger = logger -} - -//------------------------------------------------------------------------------ - -type Strings []string - -var _ orm.HooklessModel = (*Strings)(nil) -var _ types.ValueAppender = (*Strings)(nil) - -func (strings *Strings) Init() error { - if s := *strings; len(s) > 0 { - *strings = s[:0] - } - return nil -} - -func (strings *Strings) NewModel() orm.ColumnScanner { - return strings -} - -func (Strings) AddModel(_ orm.ColumnScanner) error { - return nil -} - -func (strings *Strings) ScanColumn(colIdx int, _ string, b []byte) error { - *strings = append(*strings, string(b)) - return nil -} - -func (strings Strings) AppendValue(dst []byte, quote int) []byte { - if len(strings) <= 0 { - return dst - } - - for _, s := range strings { - dst = types.AppendString(dst, s, 1) - dst = append(dst, ',') - } - dst = dst[:len(dst)-1] - return dst -} - -//------------------------------------------------------------------------------ - -type Ints []int64 - -var _ orm.HooklessModel = (*Ints)(nil) -var _ types.ValueAppender = (*Ints)(nil) - -func (ints *Ints) Init() error { - if s := *ints; len(s) > 0 { - *ints = s[:0] - } - return nil -} - -func (ints *Ints) NewModel() orm.ColumnScanner { - return ints -} - -func (Ints) AddModel(_ orm.ColumnScanner) error { - return nil -} - -func (ints *Ints) ScanColumn(colIdx int, colName string, b []byte) error { - n, err := strconv.ParseInt(internal.BytesToString(b), 10, 64) - if err != nil { - return err - } - *ints = append(*ints, n) - return nil -} - -func (ints Ints) AppendValue(dst []byte, quote int) []byte { - if len(ints) <= 0 { - return dst - } - - for _, v := range ints { - dst = strconv.AppendInt(dst, v, 10) - dst = append(dst, ',') - } - dst = dst[:len(dst)-1] - return dst -} - -//------------------------------------------------------------------------------ - -type IntSet map[int64]struct{} - -var _ orm.HooklessModel = (*IntSet)(nil) - -func (set *IntSet) Init() error { - if len(*set) > 0 { - *set = make(map[int64]struct{}) - } - return nil -} - -func (set *IntSet) NewModel() orm.ColumnScanner { - return set -} - -func (IntSet) AddModel(_ orm.ColumnScanner) error { - return nil -} - -func (setptr *IntSet) ScanColumn(colIdx int, colName string, b []byte) error { - set := *setptr - if set == nil { - *setptr = make(IntSet) - set = *setptr - } - - n, err := strconv.ParseInt(internal.BytesToString(b), 10, 64) - if err != nil { - return err - } - set[n] = struct{}{} - return nil -} diff --git a/vendor/github.com/go-pg/pg/stmt.go b/vendor/github.com/go-pg/pg/stmt.go deleted file mode 100644 index af96df78b..000000000 --- a/vendor/github.com/go-pg/pg/stmt.go +++ /dev/null @@ -1,278 +0,0 @@ -package pg - -import ( - "errors" - "sync" - "time" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/pool" - "github.com/go-pg/pg/orm" -) - -var errStmtClosed = errors.New("pg: statement is closed") - -// Stmt is a prepared statement. Stmt is safe for concurrent use by -// multiple goroutines. -type Stmt struct { - db *DB - - mu sync.Mutex - _cn *pool.Conn - inTx bool - - q string - name string - columns [][]byte - - stickyErr error -} - -// Prepare creates a prepared statement for later queries or -// executions. Multiple queries or executions may be run concurrently -// from the returned statement. -func (db *DB) Prepare(q string) (*Stmt, error) { - cn, err := db.conn() - if err != nil { - return nil, err - } - - stmt, err := prepare(db, cn, q) - if err != nil { - db.freeConn(cn, err) - return nil, err - } - - return stmt, nil -} - -func (stmt *Stmt) conn() (*pool.Conn, error) { - if stmt._cn == nil { - if stmt.stickyErr != nil { - return nil, stmt.stickyErr - } - return nil, errStmtClosed - } - return stmt._cn, nil -} - -func (stmt *Stmt) exec(params ...interface{}) (orm.Result, error) { - stmt.mu.Lock() - defer stmt.mu.Unlock() - - cn, err := stmt.conn() - if err != nil { - return nil, err - } - return stmt.extQuery(cn, stmt.name, params...) -} - -// Exec executes a prepared statement with the given parameters. -func (stmt *Stmt) Exec(params ...interface{}) (res orm.Result, err error) { - for attempt := 0; attempt <= stmt.db.opt.MaxRetries; attempt++ { - if attempt >= 1 { - time.Sleep(stmt.db.retryBackoff(attempt - 1)) - } - - start := time.Now() - res, err = stmt.exec(params...) - stmt.db.queryProcessed(stmt.db, start, stmt.q, params, attempt, res, err) - - if !stmt.db.shouldRetry(err) { - break - } - } - if err != nil { - stmt.setErr(err) - } - return -} - -// ExecOne acts like Exec, but query must affect only one row. It -// returns ErrNoRows error when query returns zero rows or -// ErrMultiRows when query returns multiple rows. -func (stmt *Stmt) ExecOne(params ...interface{}) (orm.Result, error) { - res, err := stmt.Exec(params...) - if err != nil { - return nil, err - } - - if err := internal.AssertOneRow(res.RowsAffected()); err != nil { - return nil, err - } - return res, nil -} - -func (stmt *Stmt) query(model interface{}, params ...interface{}) (orm.Result, error) { - stmt.mu.Lock() - defer stmt.mu.Unlock() - - cn, err := stmt.conn() - if err != nil { - return nil, err - } - - res, err := stmt.extQueryData(cn, stmt.name, model, stmt.columns, params...) - if err != nil { - return nil, err - } - - if mod := res.Model(); mod != nil && res.RowsReturned() > 0 { - if err = mod.AfterQuery(stmt.db); err != nil { - return res, err - } - } - - return res, nil -} - -// Query executes a prepared query statement with the given parameters. -func (stmt *Stmt) Query(model interface{}, params ...interface{}) (res orm.Result, err error) { - for attempt := 0; attempt <= stmt.db.opt.MaxRetries; attempt++ { - if attempt >= 1 { - time.Sleep(stmt.db.retryBackoff(attempt - 1)) - } - - start := time.Now() - res, err = stmt.query(model, params...) - stmt.db.queryProcessed(stmt.db, start, stmt.q, params, attempt, res, err) - - if !stmt.db.shouldRetry(err) { - break - } - } - if err != nil { - stmt.setErr(err) - } - return -} - -// QueryOne acts like Query, but query must return only one row. It -// returns ErrNoRows error when query returns zero rows or -// ErrMultiRows when query returns multiple rows. -func (stmt *Stmt) QueryOne(model interface{}, params ...interface{}) (orm.Result, error) { - mod, err := orm.NewModel(model) - if err != nil { - return nil, err - } - - res, err := stmt.Query(mod, params...) - if err != nil { - return nil, err - } - - if err := internal.AssertOneRow(res.RowsAffected()); err != nil { - return nil, err - } - return res, nil -} - -func (stmt *Stmt) setErr(e error) { - if stmt.stickyErr == nil { - stmt.stickyErr = e - } -} - -// Close closes the statement. -func (stmt *Stmt) Close() error { - stmt.mu.Lock() - defer stmt.mu.Unlock() - - if stmt._cn == nil { - return errStmtClosed - } - - err := stmt.closeStmt(stmt._cn, stmt.name) - if !stmt.inTx { - stmt.db.freeConn(stmt._cn, err) - } - stmt._cn = nil - return err -} - -func prepare(db *DB, cn *pool.Conn, q string) (*Stmt, error) { - name := cn.NextId() - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - writeParseDescribeSyncMsg(wb, name, q) - return nil - }) - if err != nil { - return nil, err - } - - var columns [][]byte - cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { - columns, err = readParseDescribeSync(rd) - return err - }) - if err != nil { - return nil, err - } - - stmt := &Stmt{ - db: db, - _cn: cn, - q: q, - name: name, - columns: columns, - } - return stmt, nil -} - -func (stmt *Stmt) extQuery(cn *pool.Conn, name string, params ...interface{}) (orm.Result, error) { - err := cn.WithWriter(stmt.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeBindExecuteMsg(wb, name, params...) - }) - if err != nil { - return nil, err - } - - var res orm.Result - err = cn.WithReader(stmt.db.opt.ReadTimeout, func(rd *pool.Reader) error { - res, err = readExtQuery(rd) - return err - }) - if err != nil { - return nil, err - } - - return res, nil -} - -func (stmt *Stmt) extQueryData( - cn *pool.Conn, name string, model interface{}, columns [][]byte, params ...interface{}, -) (orm.Result, error) { - err := cn.WithWriter(stmt.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - return writeBindExecuteMsg(wb, name, params...) - }) - if err != nil { - return nil, err - } - - var res orm.Result - err = cn.WithReader(stmt.db.opt.ReadTimeout, func(rd *pool.Reader) error { - res, err = readExtQueryData(rd, model, columns) - return err - }) - if err != nil { - return nil, err - } - - return res, nil -} - -func (stmt *Stmt) closeStmt(cn *pool.Conn, name string) error { - err := cn.WithWriter(stmt.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - writeCloseMsg(wb, name) - writeFlushMsg(wb) - return nil - }) - if err != nil { - return err - } - - err = cn.WithReader(stmt.db.opt.ReadTimeout, func(rd *pool.Reader) error { - return readCloseCompleteMsg(rd) - }) - return err -} diff --git a/vendor/github.com/go-pg/pg/tx.go b/vendor/github.com/go-pg/pg/tx.go deleted file mode 100644 index de2024c88..000000000 --- a/vendor/github.com/go-pg/pg/tx.go +++ /dev/null @@ -1,338 +0,0 @@ -package pg - -import ( - "context" - "errors" - "io" - "sync" - "time" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/pool" - "github.com/go-pg/pg/orm" -) - -var errTxDone = errors.New("pg: transaction has already been committed or rolled back") - -// Tx is an in-progress database transaction. It is safe for concurrent use -// by multiple goroutines. -// -// A transaction must end with a call to Commit or Rollback. -// -// After a call to Commit or Rollback, all operations on the transaction fail -// with ErrTxDone. -// -// The statements prepared for a transaction by calling the transaction's -// Prepare or Stmt methods are closed by the call to Commit or Rollback. -type Tx struct { - db *DB - - mu sync.Mutex - cn *pool.Conn - stmts []*Stmt -} - -var _ orm.DB = (*Tx)(nil) - -// Begin starts a transaction. Most callers should use RunInTransaction instead. -func (db *DB) Begin() (*Tx, error) { - tx := &Tx{ - db: db, - } - - cn, err := db.conn() - if err != nil { - return nil, err - } - tx.cn = cn - - if err := tx.begin(); err != nil { - return nil, err - } - - return tx, nil -} - -// RunInTransaction runs a function in a transaction. If function -// returns an error transaction is rollbacked, otherwise transaction -// is committed. -func (db *DB) RunInTransaction(fn func(*Tx) error) error { - tx, err := db.Begin() - if err != nil { - return err - } - return tx.RunInTransaction(fn) -} - -// DB returns a DB which started the Tx. -func (tx *Tx) DB() *DB { - return tx.db -} - -// Begin returns the transaction. -func (tx *Tx) Begin() (*Tx, error) { - return tx, nil -} - -// RunInTransaction runs a function in the transaction. If function -// returns an error transaction is rollbacked, otherwise transaction -// is committed. -func (tx *Tx) RunInTransaction(fn func(*Tx) error) error { - defer func() { - if err := recover(); err != nil { - _ = tx.Rollback() - panic(err) - } - }() - if err := fn(tx); err != nil { - _ = tx.Rollback() - return err - } - return tx.Commit() -} - -func (tx *Tx) conn() (*pool.Conn, error) { - if tx.cn == nil { - return nil, errTxDone - } - return tx.cn, nil -} - -func (tx *Tx) freeConn(cn *pool.Conn, err error) {} - -// Stmt returns a transaction-specific prepared statement -// from an existing statement. -func (tx *Tx) Stmt(stmt *Stmt) *Stmt { - stmt, err := tx.Prepare(stmt.q) - if err != nil { - return &Stmt{stickyErr: err} - } - return stmt -} - -// Prepare creates a prepared statement for use within a transaction. -// -// The returned statement operates within the transaction and can no longer -// be used once the transaction has been committed or rolled back. -// -// To use an existing prepared statement on this transaction, see Tx.Stmt. -func (tx *Tx) Prepare(q string) (*Stmt, error) { - tx.mu.Lock() - defer tx.mu.Unlock() - - cn, err := tx.conn() - if err != nil { - return nil, err - } - - stmt, err := prepare(tx.db, cn, q) - tx.freeConn(cn, err) - if err != nil { - return nil, err - } - - stmt.inTx = true - tx.stmts = append(tx.stmts, stmt) - - return stmt, nil -} - -// Exec is an alias for DB.Exec. -func (tx *Tx) Exec(query interface{}, params ...interface{}) (orm.Result, error) { - tx.mu.Lock() - defer tx.mu.Unlock() - return tx.exec(query, params...) -} - -func (tx *Tx) exec(query interface{}, params ...interface{}) (orm.Result, error) { - cn, err := tx.conn() - if err != nil { - return nil, err - } - - start := time.Now() - res, err := tx.db.simpleQuery(cn, query, params...) - tx.freeConn(cn, err) - tx.db.queryProcessed(tx, start, query, params, 0, res, err) - - return res, err -} - -// ExecOne is an alias for DB.ExecOne. -func (tx *Tx) ExecOne(query interface{}, params ...interface{}) (orm.Result, error) { - res, err := tx.Exec(query, params...) - if err != nil { - return nil, err - } - - if err := internal.AssertOneRow(res.RowsAffected()); err != nil { - return nil, err - } - return res, nil -} - -// Query is an alias for DB.Query. -func (tx *Tx) Query(model interface{}, query interface{}, params ...interface{}) (orm.Result, error) { - tx.mu.Lock() - defer tx.mu.Unlock() - - cn, err := tx.conn() - if err != nil { - return nil, err - } - - start := time.Now() - res, err := tx.db.simpleQueryData(cn, model, query, params...) - tx.freeConn(cn, err) - tx.db.queryProcessed(tx, start, query, params, 0, res, err) - - if err != nil { - return nil, err - } - - if mod := res.Model(); mod != nil && res.RowsReturned() > 0 { - if err = mod.AfterQuery(tx); err != nil { - return res, err - } - } - - return res, err -} - -// QueryOne is an alias for DB.QueryOne. -func (tx *Tx) QueryOne(model interface{}, query interface{}, params ...interface{}) (orm.Result, error) { - mod, err := orm.NewModel(model) - if err != nil { - return nil, err - } - - res, err := tx.Query(mod, query, params...) - if err != nil { - return nil, err - } - - if err := internal.AssertOneRow(res.RowsAffected()); err != nil { - return nil, err - } - return res, nil -} - -// Model is an alias for DB.Model. -func (tx *Tx) Model(model ...interface{}) *orm.Query { - return orm.NewQuery(tx, model...) -} - -// Select is an alias for DB.Select. -func (tx *Tx) Select(model interface{}) error { - return orm.Select(tx, model) -} - -// Insert is an alias for DB.Insert. -func (tx *Tx) Insert(model ...interface{}) error { - return orm.Insert(tx, model...) -} - -// Update is an alias for DB.Update. -func (tx *Tx) Update(model interface{}) error { - return orm.Update(tx, model) -} - -// Delete is an alias for DB.Delete. -func (tx *Tx) Delete(model interface{}) error { - return orm.Delete(tx, model) -} - -// Delete forces delete of the model with deleted_at column. -func (tx *Tx) ForceDelete(model interface{}) error { - return orm.ForceDelete(tx, model) -} - -// CreateTable is an alias for DB.CreateTable. -func (tx *Tx) CreateTable(model interface{}, opt *orm.CreateTableOptions) error { - return orm.CreateTable(tx, model, opt) -} - -// DropTable is an alias for DB.DropTable. -func (tx *Tx) DropTable(model interface{}, opt *orm.DropTableOptions) error { - return orm.DropTable(tx, model, opt) -} - -// CopyFrom is an alias for DB.CopyFrom. -func (tx *Tx) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (orm.Result, error) { - tx.mu.Lock() - defer tx.mu.Unlock() - - cn, err := tx.conn() - if err != nil { - return nil, err - } - - res, err := tx.db.copyFrom(cn, r, query, params...) - tx.freeConn(cn, err) - return res, err -} - -// CopyTo is an alias for DB.CopyTo. -func (tx *Tx) CopyTo(w io.Writer, query interface{}, params ...interface{}) (orm.Result, error) { - tx.mu.Lock() - defer tx.mu.Unlock() - - cn, err := tx.conn() - if err != nil { - return nil, err - } - - res, err := tx.db.copyTo(cn, w, query, params...) - tx.freeConn(cn, err) - return res, err -} - -func (tx *Tx) FormatQuery(dst []byte, query string, params ...interface{}) []byte { - return tx.db.FormatQuery(dst, query, params...) -} - -func (tx *Tx) begin() error { - _, err := tx.Exec("BEGIN") - if err != nil { - tx.close(err) - } - return err -} - -// Commit commits the transaction. -func (tx *Tx) Commit() error { - tx.mu.Lock() - defer tx.mu.Unlock() - - _, err := tx.exec("COMMIT") - tx.close(err) - return err -} - -// Rollback aborts the transaction. -func (tx *Tx) Rollback() error { - tx.mu.Lock() - defer tx.mu.Unlock() - - _, err := tx.exec("ROLLBACK") - tx.close(err) - return err -} - -func (tx *Tx) close(lastErr error) { - if tx.cn == nil { - return - } - - for _, stmt := range tx.stmts { - _ = stmt.Close() - } - tx.stmts = nil - - tx.db.freeConn(tx.cn, lastErr) - tx.cn = nil -} - -func (tx *Tx) Context() context.Context { - return tx.db.Context() -} diff --git a/vendor/github.com/go-pg/pg/types/append.go b/vendor/github.com/go-pg/pg/types/append.go deleted file mode 100644 index e80d124fa..000000000 --- a/vendor/github.com/go-pg/pg/types/append.go +++ /dev/null @@ -1,202 +0,0 @@ -package types - -import ( - "database/sql/driver" - "encoding/hex" - "math" - "reflect" - "strconv" - "time" -) - -func Append(b []byte, v interface{}, quote int) []byte { - switch v := v.(type) { - case nil: - return AppendNull(b, quote) - case bool: - return appendBool(b, v) - case int8: - return strconv.AppendInt(b, int64(v), 10) - case int16: - return strconv.AppendInt(b, int64(v), 10) - case int32: - return strconv.AppendInt(b, int64(v), 10) - case int64: - return strconv.AppendInt(b, int64(v), 10) - case int: - return strconv.AppendInt(b, int64(v), 10) - case uint8: - return strconv.AppendUint(b, uint64(v), 10) - case uint16: - return strconv.AppendUint(b, uint64(v), 10) - case uint32: - return strconv.AppendUint(b, uint64(v), 10) - case uint64: - return strconv.AppendUint(b, v, 10) - case uint: - return strconv.AppendUint(b, uint64(v), 10) - case float32: - return appendFloat(b, float64(v), quote) - case float64: - return appendFloat(b, v, quote) - case string: - return AppendString(b, v, quote) - case time.Time: - return AppendTime(b, v, quote) - case []byte: - return AppendBytes(b, v, quote) - case ValueAppender: - return appendAppender(b, v, quote) - case driver.Valuer: - return appendDriverValuer(b, v, quote) - default: - return appendValue(b, reflect.ValueOf(v), quote) - } -} - -func AppendError(b []byte, err error) []byte { - b = append(b, "?!("...) - b = append(b, err.Error()...) - b = append(b, ')') - return b -} - -func AppendNull(b []byte, quote int) []byte { - if quote == 1 { - return append(b, "NULL"...) - } else { - return nil - } -} - -func appendBool(dst []byte, v bool) []byte { - if v { - return append(dst, "TRUE"...) - } - return append(dst, "FALSE"...) -} - -func appendFloat(dst []byte, v float64, quote int) []byte { - switch { - case math.IsNaN(v): - if quote == 1 { - return append(dst, "'NaN'"...) - } - return append(dst, "NaN"...) - case math.IsInf(v, 1): - if quote == 1 { - return append(dst, "'Infinity'"...) - } - return append(dst, "Infinity"...) - case math.IsInf(v, -1): - if quote == 1 { - return append(dst, "'-Infinity'"...) - } - return append(dst, "-Infinity"...) - default: - return strconv.AppendFloat(dst, v, 'f', -1, 64) - } -} - -func AppendString(b []byte, s string, quote int) []byte { - if quote == 2 { - b = append(b, '"') - } else if quote == 1 { - b = append(b, '\'') - } - - for i := 0; i < len(s); i++ { - c := s[i] - - if c == '\000' { - continue - } - - if quote >= 1 { - if c == '\'' { - b = append(b, '\'', '\'') - continue - } - } - - if quote == 2 { - if c == '"' { - b = append(b, '\\', '"') - continue - } - if c == '\\' { - b = append(b, '\\', '\\') - continue - } - } - - b = append(b, c) - } - - if quote >= 2 { - b = append(b, '"') - } else if quote == 1 { - b = append(b, '\'') - } - - return b -} - -func AppendBytes(b []byte, bytes []byte, quote int) []byte { - if bytes == nil { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - tmp := make([]byte, hex.EncodedLen(len(bytes))) - hex.Encode(tmp, bytes) - b = append(b, "\\x"...) - b = append(b, tmp...) - - if quote == 1 { - b = append(b, '\'') - } - - return b -} - -func AppendStringStringMap(b []byte, m map[string]string, quote int) []byte { - if m == nil { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - for key, value := range m { - b = AppendString(b, key, 2) - b = append(b, '=', '>') - b = AppendString(b, value, 2) - b = append(b, ',') - } - if len(m) > 0 { - b = b[:len(b)-1] // Strip trailing comma. - } - - if quote == 1 { - b = append(b, '\'') - } - - return b -} - -func appendDriverValuer(b []byte, v driver.Valuer, quote int) []byte { - value, err := v.Value() - if err != nil { - return AppendError(b, err) - } - return Append(b, value, quote) -} - -func appendAppender(b []byte, v ValueAppender, quote int) []byte { - return v.AppendValue(b, quote) -} diff --git a/vendor/github.com/go-pg/pg/types/append_array.go b/vendor/github.com/go-pg/pg/types/append_array.go deleted file mode 100644 index f554eef12..000000000 --- a/vendor/github.com/go-pg/pg/types/append_array.go +++ /dev/null @@ -1,190 +0,0 @@ -package types - -import ( - "reflect" - "strconv" -) - -var stringType = reflect.TypeOf((*string)(nil)).Elem() -var sliceStringType = reflect.TypeOf([]string(nil)) - -var intType = reflect.TypeOf((*int)(nil)).Elem() -var sliceIntType = reflect.TypeOf([]int(nil)) - -var int64Type = reflect.TypeOf((*int64)(nil)).Elem() -var sliceInt64Type = reflect.TypeOf([]int64(nil)) - -var float64Type = reflect.TypeOf((*float64)(nil)).Elem() -var sliceFloat64Type = reflect.TypeOf([]float64(nil)) - -func ArrayAppender(typ reflect.Type) AppenderFunc { - elemType := typ.Elem() - - switch elemType { - case stringType: - return appendSliceStringValue - case intType: - return appendSliceIntValue - case int64Type: - return appendSliceInt64Value - case float64Type: - return appendSliceFloat64Value - } - - appendElem := appender(elemType, true) - return func(b []byte, v reflect.Value, quote int) []byte { - if v.IsNil() { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - b = append(b, '{') - for i := 0; i < v.Len(); i++ { - elem := v.Index(i) - b = appendElem(b, elem, 2) - b = append(b, ',') - } - if v.Len() > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - if quote == 1 { - b = append(b, '\'') - } - - return b - } -} - -func appendSliceStringValue(b []byte, v reflect.Value, quote int) []byte { - ss := v.Convert(sliceStringType).Interface().([]string) - return appendSliceString(b, ss, quote) -} - -func appendSliceString(b []byte, ss []string, quote int) []byte { - if ss == nil { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - b = append(b, '{') - for _, s := range ss { - b = AppendString(b, s, 2) - b = append(b, ',') - } - if len(ss) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - if quote == 1 { - b = append(b, '\'') - } - - return b -} - -func appendSliceIntValue(b []byte, v reflect.Value, quote int) []byte { - ints := v.Convert(sliceIntType).Interface().([]int) - return appendSliceInt(b, ints, quote) -} - -func appendSliceInt(b []byte, ints []int, quote int) []byte { - if ints == nil { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - b = append(b, '{') - for _, n := range ints { - b = strconv.AppendInt(b, int64(n), 10) - b = append(b, ',') - } - if len(ints) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - if quote == 1 { - b = append(b, '\'') - } - - return b -} - -func appendSliceInt64Value(b []byte, v reflect.Value, quote int) []byte { - ints := v.Convert(sliceInt64Type).Interface().([]int64) - return appendSliceInt64(b, ints, quote) -} - -func appendSliceInt64(b []byte, ints []int64, quote int) []byte { - if ints == nil { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - b = append(b, '{') - for _, n := range ints { - b = strconv.AppendInt(b, n, 10) - b = append(b, ',') - } - if len(ints) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - if quote == 1 { - b = append(b, '\'') - } - - return b -} - -func appendSliceFloat64Value(b []byte, v reflect.Value, quote int) []byte { - floats := v.Convert(sliceFloat64Type).Interface().([]float64) - return appendSliceFloat64(b, floats, quote) -} - -func appendSliceFloat64(b []byte, floats []float64, quote int) []byte { - if floats == nil { - return AppendNull(b, quote) - } - - if quote == 1 { - b = append(b, '\'') - } - - b = append(b, '{') - for _, n := range floats { - b = appendFloat(b, n, 2) - b = append(b, ',') - } - if len(floats) > 0 { - b[len(b)-1] = '}' // Replace trailing comma. - } else { - b = append(b, '}') - } - - if quote == 1 { - b = append(b, '\'') - } - - return b -} diff --git a/vendor/github.com/go-pg/pg/types/append_field.go b/vendor/github.com/go-pg/pg/types/append_field.go deleted file mode 100644 index 2fa86dcef..000000000 --- a/vendor/github.com/go-pg/pg/types/append_field.go +++ /dev/null @@ -1,52 +0,0 @@ -package types - -import "github.com/go-pg/pg/internal/parser" - -func AppendField(b []byte, field string, quote int) []byte { - return appendField(b, parser.NewString(field), quote) -} - -func AppendFieldBytes(b []byte, field []byte, quote int) []byte { - return appendField(b, parser.New(field), quote) -} - -func appendField(b []byte, p *parser.Parser, quote int) []byte { - var quoted bool - for p.Valid() { - c := p.Read() - switch c { - case '*': - if !quoted { - b = append(b, '*') - continue - } - case '.': - if quoted && quote == 1 { - b = append(b, '"') - quoted = false - } - b = append(b, '.') - if p.Skip('*') { - b = append(b, '*') - } else if quote == 1 { - b = append(b, '"') - quoted = true - } - continue - } - - if !quoted && quote == 1 { - b = append(b, '"') - quoted = true - } - if c == '"' { - b = append(b, '"', '"') - } else { - b = append(b, c) - } - } - if quoted && quote == 1 { - b = append(b, '"') - } - return b -} diff --git a/vendor/github.com/go-pg/pg/types/append_jsonb.go b/vendor/github.com/go-pg/pg/types/append_jsonb.go deleted file mode 100644 index 3bede711f..000000000 --- a/vendor/github.com/go-pg/pg/types/append_jsonb.go +++ /dev/null @@ -1,41 +0,0 @@ -package types - -import "github.com/go-pg/pg/internal/parser" - -func AppendJSONB(b, jsonb []byte, quote int) []byte { - if quote == 1 { - b = append(b, '\'') - } - - p := parser.New(jsonb) - for p.Valid() { - c := p.Read() - switch c { - case '\'': - if quote == 1 { - b = append(b, '\'', '\'') - } else { - b = append(b, '\'') - } - case '\000': - continue - case '\\': - if p.SkipBytes([]byte("u0000")) { - b = append(b, "\\\\u0000"...) - } else { - b = append(b, '\\') - if p.Valid() { - b = append(b, p.Read()) - } - } - default: - b = append(b, c) - } - } - - if quote == 1 { - b = append(b, '\'') - } - - return b -} diff --git a/vendor/github.com/go-pg/pg/types/append_value.go b/vendor/github.com/go-pg/pg/types/append_value.go deleted file mode 100644 index bd1d54338..000000000 --- a/vendor/github.com/go-pg/pg/types/append_value.go +++ /dev/null @@ -1,181 +0,0 @@ -package types - -import ( - "database/sql/driver" - "encoding/json" - "net" - "reflect" - "strconv" - "time" -) - -var driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() -var appenderType = reflect.TypeOf((*ValueAppender)(nil)).Elem() - -type AppenderFunc func([]byte, reflect.Value, int) []byte - -var valueAppenders []AppenderFunc - -func init() { - valueAppenders = []AppenderFunc{ - reflect.Bool: appendBoolValue, - reflect.Int: appendIntValue, - reflect.Int8: appendIntValue, - reflect.Int16: appendIntValue, - reflect.Int32: appendIntValue, - reflect.Int64: appendIntValue, - reflect.Uint: appendUintValue, - reflect.Uint8: appendUintValue, - reflect.Uint16: appendUintValue, - reflect.Uint32: appendUintValue, - reflect.Uint64: appendUintValue, - reflect.Uintptr: nil, - reflect.Float32: appendFloatValue, - reflect.Float64: appendFloatValue, - reflect.Complex64: nil, - reflect.Complex128: nil, - reflect.Array: nil, - reflect.Chan: nil, - reflect.Func: nil, - reflect.Interface: appendIfaceValue, - reflect.Map: appendJSONValue, - reflect.Ptr: nil, - reflect.Slice: appendJSONValue, - reflect.String: appendStringValue, - reflect.Struct: appendStructValue, - reflect.UnsafePointer: nil, - } -} - -func Appender(typ reflect.Type) AppenderFunc { - return appender(typ, false) -} - -func appender(typ reflect.Type, pgArray bool) AppenderFunc { - switch typ { - case timeType: - return appendTimeValue - case ipType: - return appendIPValue - case ipNetType: - return appendIPNetValue - } - - if typ.Implements(appenderType) { - return appendAppenderValue - } - - if typ.Implements(driverValuerType) { - return appendDriverValuerValue - } - - kind := typ.Kind() - switch kind { - case reflect.Ptr: - return ptrAppenderFunc(typ) - case reflect.Slice: - if typ.Elem().Kind() == reflect.Uint8 { - return appendBytesValue - } - if pgArray { - return ArrayAppender(typ) - } - case reflect.Array: - if typ.Elem().Kind() == reflect.Uint8 { - return appendArrayBytesValue - } - } - return valueAppenders[kind] -} - -func ptrAppenderFunc(typ reflect.Type) AppenderFunc { - appender := Appender(typ.Elem()) - return func(b []byte, v reflect.Value, quote int) []byte { - if v.IsNil() { - return AppendNull(b, quote) - } - return appender(b, v.Elem(), quote) - } -} - -func appendValue(b []byte, v reflect.Value, quote int) []byte { - if v.Kind() == reflect.Ptr { - if v.IsNil() { - return AppendNull(b, quote) - } - return appendValue(b, v.Elem(), quote) - } - - appender := Appender(v.Type()) - return appender(b, v, quote) -} - -func appendIfaceValue(b []byte, v reflect.Value, quote int) []byte { - return Append(b, v.Interface(), quote) -} - -func appendBoolValue(b []byte, v reflect.Value, _ int) []byte { - return appendBool(b, v.Bool()) -} - -func appendIntValue(b []byte, v reflect.Value, _ int) []byte { - return strconv.AppendInt(b, v.Int(), 10) -} - -func appendUintValue(b []byte, v reflect.Value, _ int) []byte { - return strconv.AppendUint(b, v.Uint(), 10) -} - -func appendFloatValue(b []byte, v reflect.Value, quote int) []byte { - return appendFloat(b, v.Float(), quote) -} - -func appendBytesValue(b []byte, v reflect.Value, quote int) []byte { - return AppendBytes(b, v.Bytes(), quote) -} - -func appendArrayBytesValue(b []byte, v reflect.Value, quote int) []byte { - return AppendBytes(b, v.Slice(0, v.Len()).Bytes(), quote) -} - -func appendStringValue(b []byte, v reflect.Value, quote int) []byte { - return AppendString(b, v.String(), quote) -} - -func appendStructValue(b []byte, v reflect.Value, quote int) []byte { - if v.Type() == timeType { - return appendTimeValue(b, v, quote) - } - return appendJSONValue(b, v, quote) -} - -func appendJSONValue(b []byte, v reflect.Value, quote int) []byte { - bytes, err := json.Marshal(v.Interface()) - if err != nil { - return AppendError(b, err) - } - return AppendJSONB(b, bytes, quote) -} - -func appendTimeValue(b []byte, v reflect.Value, quote int) []byte { - tm := v.Interface().(time.Time) - return AppendTime(b, tm, quote) -} - -func appendIPValue(b []byte, v reflect.Value, quote int) []byte { - ip := v.Interface().(net.IP) - return AppendString(b, ip.String(), quote) -} - -func appendIPNetValue(b []byte, v reflect.Value, quote int) []byte { - ipnet := v.Interface().(net.IPNet) - return AppendString(b, ipnet.String(), quote) -} - -func appendAppenderValue(b []byte, v reflect.Value, quote int) []byte { - return appendAppender(b, v.Interface().(ValueAppender), quote) -} - -func appendDriverValuerValue(b []byte, v reflect.Value, quote int) []byte { - return appendDriverValuer(b, v.Interface().(driver.Valuer), quote) -} diff --git a/vendor/github.com/go-pg/pg/types/array.go b/vendor/github.com/go-pg/pg/types/array.go deleted file mode 100644 index 613b6c97b..000000000 --- a/vendor/github.com/go-pg/pg/types/array.go +++ /dev/null @@ -1,52 +0,0 @@ -package types - -import ( - "database/sql" - "fmt" - "reflect" -) - -type Array struct { - v reflect.Value - - append AppenderFunc - scan ScannerFunc -} - -var _ ValueAppender = (*Array)(nil) -var _ sql.Scanner = (*Array)(nil) - -func NewArray(vi interface{}) *Array { - v := reflect.ValueOf(vi) - if !v.IsValid() { - panic(fmt.Errorf("pg.Array(nil)")) - } - v = reflect.Indirect(v) - if v.Kind() != reflect.Slice { - panic(fmt.Errorf("pg.Array(unsupported %s)", v.Type())) - } - return &Array{ - v: v, - - append: ArrayAppender(v.Type()), - scan: ArrayScanner(v.Type()), - } -} - -func (a *Array) Value() interface{} { - if a.v.IsValid() { - return a.v.Interface() - } - return nil -} - -func (a *Array) AppendValue(b []byte, quote int) []byte { - return a.append(b, a.v, quote) -} - -func (a *Array) Scan(b interface{}) error { - if b == nil { - return a.scan(a.v, nil) - } - return a.scan(a.v, b.([]byte)) -} diff --git a/vendor/github.com/go-pg/pg/types/hstore.go b/vendor/github.com/go-pg/pg/types/hstore.go deleted file mode 100644 index b6241e67e..000000000 --- a/vendor/github.com/go-pg/pg/types/hstore.go +++ /dev/null @@ -1,52 +0,0 @@ -package types - -import ( - "database/sql" - "fmt" - "reflect" -) - -type Hstore struct { - v reflect.Value - - append AppenderFunc - scan ScannerFunc -} - -var _ ValueAppender = (*Hstore)(nil) -var _ sql.Scanner = (*Hstore)(nil) - -func NewHstore(vi interface{}) *Hstore { - v := reflect.ValueOf(vi) - if !v.IsValid() { - panic(fmt.Errorf("pg.Hstore(nil)")) - } - v = reflect.Indirect(v) - if v.Kind() != reflect.Map { - panic(fmt.Errorf("pg.Hstore(unsupported %s)", v.Type())) - } - return &Hstore{ - v: v, - - append: HstoreAppender(v.Type()), - scan: HstoreScanner(v.Type()), - } -} - -func (h *Hstore) Value() interface{} { - if h.v.IsValid() { - return h.v.Interface() - } - return nil -} - -func (h *Hstore) AppendValue(b []byte, quote int) []byte { - return h.append(b, h.v, quote) -} - -func (h *Hstore) Scan(b interface{}) error { - if b == nil { - return h.scan(h.v, nil) - } - return h.scan(h.v, b.([]byte)) -} diff --git a/vendor/github.com/go-pg/pg/types/in_op.go b/vendor/github.com/go-pg/pg/types/in_op.go deleted file mode 100644 index bfe395c67..000000000 --- a/vendor/github.com/go-pg/pg/types/in_op.go +++ /dev/null @@ -1,49 +0,0 @@ -package types - -import ( - "reflect" -) - -type inOp struct { - slice reflect.Value -} - -var _ ValueAppender = (*inOp)(nil) - -func In(values ...interface{}) ValueAppender { - return &inOp{ - slice: reflect.ValueOf(values), - } -} - -func InSlice(slice interface{}) ValueAppender { - return &inOp{ - slice: reflect.ValueOf(slice), - } -} - -func (in *inOp) AppendValue(b []byte, quote int) []byte { - return appendIn(b, in.slice, quote) -} - -func appendIn(b []byte, slice reflect.Value, quote int) []byte { - for i := 0; i < slice.Len(); i++ { - if i > 0 { - b = append(b, ',') - } - - elem := slice.Index(i) - if elem.Kind() == reflect.Interface { - elem = elem.Elem() - } - - if elem.Kind() == reflect.Slice { - b = append(b, '(') - b = appendIn(b, elem, quote) - b = append(b, ')') - } else { - b = appendValue(b, elem, quote) - } - } - return b -} diff --git a/vendor/github.com/go-pg/pg/types/interface.go b/vendor/github.com/go-pg/pg/types/interface.go deleted file mode 100644 index b62ad7e52..000000000 --- a/vendor/github.com/go-pg/pg/types/interface.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -type ValueAppender interface { - AppendValue(b []byte, quote int) []byte -} - -//------------------------------------------------------------------------------ - -// Q represents safe SQL query. -type Q string - -var _ ValueAppender = Q("") - -func (q Q) AppendValue(b []byte, quote int) []byte { - return append(b, q...) -} - -//------------------------------------------------------------------------------ - -// F represents a SQL field, e.g. table or column name. -type F string - -var _ ValueAppender = F("") - -func (f F) AppendValue(b []byte, quote int) []byte { - return AppendField(b, string(f), quote) -} diff --git a/vendor/github.com/go-pg/pg/types/scan.go b/vendor/github.com/go-pg/pg/types/scan.go deleted file mode 100644 index 602f84810..000000000 --- a/vendor/github.com/go-pg/pg/types/scan.go +++ /dev/null @@ -1,83 +0,0 @@ -package types - -import ( - "database/sql" - "encoding/hex" - "errors" - "fmt" - "reflect" - "time" - - "github.com/go-pg/pg/internal" -) - -func Scan(v interface{}, b []byte) error { - switch v := v.(type) { - case *string: - *v = string(b) - return nil - case *[]byte: - if b == nil { - *v = nil - return nil - } - var err error - *v, err = ScanBytes(b) - return err - case *int: - if b == nil { - *v = 0 - return nil - } - var err error - *v, err = internal.Atoi(b) - return err - case *int64: - if b == nil { - *v = 0 - return nil - } - var err error - *v, err = internal.ParseInt(b, 10, 64) - return err - case *time.Time: - if b == nil { - *v = time.Time{} - return nil - } - var err error - *v, err = ParseTime(b) - return err - } - - vv := reflect.ValueOf(v) - if !vv.IsValid() { - return errors.New("pg: Scan(nil)") - } - if vv.Kind() != reflect.Ptr { - return fmt.Errorf("pg: Scan(nonsettable %T)", v) - } - vv = vv.Elem() - if !vv.IsValid() { - return fmt.Errorf("pg: Scan(nonsettable %T)", v) - } - return ScanValue(vv, b) -} - -func scanSQLScanner(scanner sql.Scanner, b []byte) error { - if b == nil { - return scanner.Scan(nil) - } - return scanner.Scan(b) -} - -func ScanBytes(b []byte) ([]byte, error) { - if len(b) < 2 { - return nil, fmt.Errorf("pg: can't parse bytes: %q", b) - } - - b = b[2:] // Trim off "\\x". - tmp := make([]byte, hex.DecodedLen(len(b))) - _, err := hex.Decode(tmp, b) - return tmp, err -} diff --git a/vendor/github.com/go-pg/pg/types/scan_array.go b/vendor/github.com/go-pg/pg/types/scan_array.go deleted file mode 100644 index 2f000a444..000000000 --- a/vendor/github.com/go-pg/pg/types/scan_array.go +++ /dev/null @@ -1,197 +0,0 @@ -package types - -import ( - "fmt" - "reflect" - - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/parser" -) - -func ArrayScanner(typ reflect.Type) ScannerFunc { - elemType := typ.Elem() - - switch elemType { - case stringType: - return scanSliceStringValue - case intType: - return scanSliceIntValue - case int64Type: - return scanSliceInt64Value - case float64Type: - return scanSliceFloat64Value - } - - scanElem := scanner(elemType, true) - return func(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - - if b == nil { - if !v.IsNil() { - v.Set(reflect.Zero(v.Type())) - } - return nil - } - - if v.IsNil() { - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) - } else if v.Len() > 0 { - v.Set(v.Slice(0, 0)) - } - - p := parser.NewArrayParser(b) - nextValue := internal.MakeSliceNextElemFunc(v) - for p.Valid() { - elem, err := p.NextElem() - if err != nil { - return err - } - - elemValue := nextValue() - err = scanElem(elemValue, elem) - if err != nil { - return err - } - } - - return nil - } -} - -func scanSliceStringValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - strings, err := decodeSliceString(b) - if err != nil { - return err - } - v.Set(reflect.ValueOf(strings)) - return nil -} - -func decodeSliceString(b []byte) ([]string, error) { - if b == nil { - return nil, nil - } - p := parser.NewArrayParser(b) - s := make([]string, 0) - for p.Valid() { - elem, err := p.NextElem() - if err != nil { - return nil, err - } - s = append(s, string(elem)) - } - return s, nil -} - -func scanSliceIntValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - ints, err := decodeSliceInt(b) - if err != nil { - return err - } - v.Set(reflect.ValueOf(ints)) - return nil -} - -func decodeSliceInt(b []byte) ([]int, error) { - if b == nil { - return nil, nil - } - p := parser.NewArrayParser(b) - slice := make([]int, 0) - for p.Valid() { - elem, err := p.NextElem() - if err != nil { - return nil, err - } - if elem == nil { - slice = append(slice, 0) - continue - } - n, err := internal.Atoi(elem) - if err != nil { - return nil, err - } - slice = append(slice, n) - } - return slice, nil -} - -func scanSliceInt64Value(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - ints, err := decodeSliceInt64(b) - if err != nil { - return err - } - v.Set(reflect.ValueOf(ints)) - return nil -} - -func decodeSliceInt64(b []byte) ([]int64, error) { - if b == nil { - return nil, nil - } - p := parser.NewArrayParser(b) - slice := make([]int64, 0) - for p.Valid() { - elem, err := p.NextElem() - if err != nil { - return nil, err - } - if elem == nil { - slice = append(slice, 0) - continue - } - n, err := internal.ParseInt(elem, 10, 64) - if err != nil { - return nil, err - } - slice = append(slice, n) - } - return slice, nil -} - -func scanSliceFloat64Value(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - floats, err := decodeSliceFloat64(b) - if err != nil { - return err - } - v.Set(reflect.ValueOf(floats)) - return nil -} - -func decodeSliceFloat64(b []byte) ([]float64, error) { - if b == nil { - return nil, nil - } - p := parser.NewArrayParser(b) - slice := make([]float64, 0) - for p.Valid() { - elem, err := p.NextElem() - if err != nil { - return nil, err - } - if elem == nil { - slice = append(slice, 0) - continue - } - n, err := internal.ParseFloat(elem, 64) - if err != nil { - return nil, err - } - slice = append(slice, n) - } - return slice, nil -} diff --git a/vendor/github.com/go-pg/pg/types/scan_value.go b/vendor/github.com/go-pg/pg/types/scan_value.go deleted file mode 100644 index 0ff35f444..000000000 --- a/vendor/github.com/go-pg/pg/types/scan_value.go +++ /dev/null @@ -1,304 +0,0 @@ -package types - -import ( - "database/sql" - "encoding/json" - "errors" - "fmt" - "net" - "reflect" - "time" - - "github.com/go-pg/pg/internal" -) - -var scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem() -var timeType = reflect.TypeOf((*time.Time)(nil)).Elem() -var ipType = reflect.TypeOf((*net.IP)(nil)).Elem() -var ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem() - -type ScannerFunc func(reflect.Value, []byte) error - -var valueScanners []ScannerFunc - -func init() { - valueScanners = []ScannerFunc{ - reflect.Bool: scanBoolValue, - reflect.Int: scanIntValue, - reflect.Int8: scanIntValue, - reflect.Int16: scanIntValue, - reflect.Int32: scanIntValue, - reflect.Int64: scanIntValue, - reflect.Uint: scanUintValue, - reflect.Uint8: scanUintValue, - reflect.Uint16: scanUintValue, - reflect.Uint32: scanUintValue, - reflect.Uint64: scanUintValue, - reflect.Uintptr: nil, - reflect.Float32: scanFloatValue, - reflect.Float64: scanFloatValue, - reflect.Complex64: nil, - reflect.Complex128: nil, - reflect.Array: nil, - reflect.Chan: nil, - reflect.Func: nil, - reflect.Interface: scanIfaceValue, - reflect.Map: scanJSONValue, - reflect.Ptr: nil, - reflect.Slice: scanJSONValue, - reflect.String: scanStringValue, - reflect.Struct: scanJSONValue, - reflect.UnsafePointer: nil, - } -} - -func Scanner(typ reflect.Type) ScannerFunc { - return scanner(typ, false) -} - -func scanner(typ reflect.Type, pgArray bool) ScannerFunc { - switch typ { - case timeType: - return scanTimeValue - case ipType: - return scanIPValue - case ipNetType: - return scanIPNetValue - } - - if typ.Implements(scannerType) { - return scanSQLScannerValue - } - if reflect.PtrTo(typ).Implements(scannerType) { - return scanSQLScannerAddrValue - } - - kind := typ.Kind() - switch kind { - case reflect.Ptr: - return ptrScannerFunc(typ) - case reflect.Slice: - if typ.Elem().Kind() == reflect.Uint8 { - return scanBytesValue - } - if pgArray { - return ArrayScanner(typ) - } - } - return valueScanners[kind] -} - -func ptrScannerFunc(typ reflect.Type) ScannerFunc { - scanner := Scanner(typ.Elem()) - return func(v reflect.Value, b []byte) error { - if scanner == nil { - return fmt.Errorf("pg: Scan(unsupported %s)", v.Type()) - } - if b == nil { - if v.IsNil() { - return nil - } - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - v.Set(reflect.Zero(v.Type())) - return nil - } - if v.IsNil() { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - v.Set(reflect.New(v.Type().Elem())) - } - return scanner(v.Elem(), b) - } -} - -func scanIfaceValue(v reflect.Value, b []byte) error { - if v.IsNil() { - return scanJSONValue(v, b) - } - return ScanValue(v.Elem(), b) -} - -func ScanValue(v reflect.Value, b []byte) error { - if !v.IsValid() { - return errors.New("pg: Scan(nil)") - } - - scanner := Scanner(v.Type()) - if scanner != nil { - return scanner(v, b) - } - - if v.Kind() == reflect.Interface { - return errors.New("pg: Scan(nil)") - } - return fmt.Errorf("pg: Scan(unsupported %s)", v.Type()) -} - -func scanBoolValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.SetBool(false) - return nil - } - v.SetBool(len(b) == 1 && (b[0] == 't' || b[0] == '1')) - return nil -} - -func scanIntValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.SetInt(0) - return nil - } - n, err := internal.ParseInt(b, 10, 64) - if err != nil { - return err - } - v.SetInt(n) - return nil -} - -func scanUintValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.SetUint(0) - return nil - } - n, err := internal.ParseUint(b, 10, 64) - if err != nil { - return err - } - v.SetUint(n) - return nil -} - -func scanFloatValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.SetFloat(0) - return nil - } - n, err := internal.ParseFloat(b, 64) - if err != nil { - return err - } - v.SetFloat(n) - return nil -} - -func scanStringValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - v.SetString(string(b)) - return nil -} - -func scanJSONValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.Set(reflect.New(v.Type()).Elem()) - return nil - } - return json.Unmarshal(b, v.Addr().Interface()) -} - -var zeroTimeValue = reflect.ValueOf(time.Time{}) - -func scanTimeValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.Set(zeroTimeValue) - return nil - } - tm, err := ParseTime(b) - if err != nil { - return err - } - v.Set(reflect.ValueOf(tm)) - return nil -} - -func scanIPValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - return nil - } - ip := net.ParseIP(internal.BytesToString(b)) - if ip == nil { - return fmt.Errorf("pg: invalid ip=%q", b) - } - v.Set(reflect.ValueOf(ip)) - return nil -} - -var zeroIPNetValue = reflect.ValueOf(net.IPNet{}) - -func scanIPNetValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.Set(zeroIPNetValue) - return nil - } - _, ipnet, err := net.ParseCIDR(internal.BytesToString(b)) - if err != nil { - return err - } - v.Set(reflect.ValueOf(*ipnet)) - return nil -} - -func scanBytesValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - if b == nil { - v.SetBytes(nil) - return nil - } - bs, err := ScanBytes(b) - if err != nil { - return err - } - v.SetBytes(bs) - return nil -} - -func scanSQLScannerValue(v reflect.Value, b []byte) error { - if b == nil { - if v.IsNil() { - return nil - } - return scanSQLScanner(v.Interface().(sql.Scanner), nil) - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - return scanSQLScanner(v.Interface().(sql.Scanner), b) -} - -func scanSQLScannerAddrValue(v reflect.Value, b []byte) error { - if !v.CanAddr() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - return scanSQLScanner(v.Addr().Interface().(sql.Scanner), b) -} diff --git a/vendor/github.com/go-pg/pg/v10/.golangci.yml b/vendor/github.com/go-pg/pg/v10/.golangci.yml new file mode 100644 index 000000000..e2b5ce924 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/.golangci.yml @@ -0,0 +1,18 @@ +run: + concurrency: 8 + deadline: 5m + tests: false +linters: + enable-all: true + disable: + - gochecknoglobals + - gocognit + - gomnd + - wsl + - funlen + - godox + - goerr113 + - exhaustive + - nestif + - gofumpt + - goconst diff --git a/vendor/github.com/go-pg/pg/v10/.prettierrc b/vendor/github.com/go-pg/pg/v10/.prettierrc new file mode 100644 index 000000000..8b7f044ad --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/.prettierrc @@ -0,0 +1,4 @@ +semi: false +singleQuote: true +proseWrap: always +printWidth: 100 diff --git a/vendor/github.com/go-pg/pg/v10/CHANGELOG.md b/vendor/github.com/go-pg/pg/v10/CHANGELOG.md new file mode 100644 index 000000000..78d0c1d8f --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/CHANGELOG.md @@ -0,0 +1,242 @@ +# Maintenance mode + +go-pg is in a maintenance mode and only critical issues are addressed. New development happens in +[**Bun**](https://bun.uptrace.dev/guide/pg-migration.html) repo which offers similar functionality +but works with PostgreSQL, MySQL, and SQLite. + +--- + +# Changelog + +## v10.12.0 + +- Fixed invalid pointer dereference when accessing results ([#1990](https://github.com/go-pg/pg/pull/1990)) +- Updated minimum Golang version to v1.19.0 + go.mod cleanup ([#1992](https://github.com/go-pg/pg/pull/1992)) +- Bumped golang.org/x/net from 0.10.0 to 0.17.0 ([#1993](https://github.com/go-pg/pg/pull/1993)) +- Bumped gopkg.in/yaml.v3 from 3.0.0-20200313102051-9f266ea9e77c to 3.0.0 ([#1994](https://github.com/go-pg/pg/pull/1994)) + +Thank you [@fernandez14](https://github.com/fernandez14) + +## v10.11.2 + +- Improved memory allocation when working with multi-byte characters in `appendRune` ([#1988](https://github.com/go-pg/pg/pull/1988)) +- Added `ToURL` to `*Options` ([#1934](https://github.com/go-pg/pg/pull/1934)) + +Thank you @dillonstreator and @MateusVeloso! + +## v10.11.1 + +- Fixed bug with how cancelled contexts are handled in SingleConnPool connections ([#1981](https://github.com/go-pg/pg/pull/1981)) + +Thank you @xin-tsla! + +## v10.11.0 + +- Updated dependency `mellium.im/sasl` from 0.2.1 to 0.3.1. ([#1969](https://github.com/go-pg/pg/pull/1969)) + +## v10.10.7 + +- Fixed race condition in notify listener. +- Add shortcut `WhereInOr`. +- Fixed bug in sending cancel request to terminate long running query. + +## v10.10.6 + +- Updated OpenTelemetry to v1.0.0. + +## v10.10 + +- Removed extra OpenTelemetry spans from go-pg core. Now go-pg instrumentation only adds a single + span with a SQL query (instead of 4 spans). There are multiple reasons behind this decision: + + - Traces become smaller and less noisy. + - [Bun](https://github.com/uptrace/bun) can't support the same level of instrumentation and it is + nice to keep projects synced. + - It may be costly to process those 3 extra spans for each query. + + Eventually we hope to replace the information that we no longer collect with OpenTelemetry + Metrics. + +## v10.9 + +- To make updating easier, extra modules now have the same version as go-pg does. That means that + you need to update your imports: + +``` +github.com/go-pg/pg/extra/pgdebug -> github.com/go-pg/pg/extra/pgdebug/v10 +github.com/go-pg/pg/extra/pgotel -> github.com/go-pg/pg/extra/pgotel/v10 +github.com/go-pg/pg/extra/pgsegment -> github.com/go-pg/pg/extra/pgsegment/v10 +``` + +- Exported `pg.Query` which should be used instead of `orm.Query`. +- Added `pg.DBI` which is a DB interface implemented by `pg.DB` and `pg.Tx`. + +## v10 + +### Resources + +- Docs at https://pg.uptrace.dev/ powered by [mkdocs](https://github.com/squidfunk/mkdocs-material). +- [RealWorld example application](https://github.com/uptrace/go-realworld-example-app). +- [Discord](https://discord.gg/rWtp5Aj). + +### Features + +- `Select`, `Insert`, and `Update` support `map[string]interface{}`. `Select` also supports + `[]map[string]interface{}`. + +```go +var mm []map[string]interface{} +err := db.Model((*User)(nil)).Limit(10).Select(&mm) +``` + +- Columns that start with `_` are ignored if there is no destination field. +- Optional [faster json encoding](https://github.com/go-pg/pgext). +- Added [pgext.OpenTelemetryHook](https://github.com/go-pg/pgext) that adds + [OpenTelemetry instrumentation](https://pg.uptrace.dev/tracing/). +- Added [pgext.DebugHook](https://github.com/go-pg/pgext) that logs failed queries. +- Added `db.Ping` to check if database is healthy. + +### Changes + +- ORM relations are reworked and now require `rel` tag option (but existing code will continue + working until v11). Supported options: + - `pg:"rel:has-one"` - has one relation. + - `pg:"rel:belongs-to"` - belongs to relation. + - `pg:"rel:has-many"` - has many relation. + - `pg:"many2many:book_genres"` - many to many relation. +- Changed `pg.QueryHook` to return temp byte slice to reduce memory usage. +- `,msgpack` struct tag marshals data in MessagePack format using + https://github.com/vmihailenco/msgpack +- Empty slices and maps are no longer marshaled as `NULL`. Nil slices and maps are still marshaled + as `NULL`. +- Changed `UpdateNotZero` to include zero fields with `pg:",use_zero"` tag. Consider using + `Model(*map[string]interface{})` for inserts and updates. +- `joinFK` is deprecated in favor of `join_fk`. +- `partitionBy` is deprecated in favor of `partition_by`. +- ORM shortcuts are removed: + - `db.Select(model)` becomes `db.Model(model).WherePK().Select()`. + - `db.Insert(model)` becomes `db.Model(model).Insert()`. + - `db.Update(model)` becomes `db.Model(model).WherePK().Update()`. + - `db.Delete(model)` becomes `db.Model(model).WherePK().Delete()`. +- Deprecated types and funcs are removed. +- `WhereStruct` is removed. + +## v9 + +- `pg:",notnull"` is reworked. Now it means SQL `NOT NULL` constraint and nothing more. +- Added `pg:",use_zero"` to prevent go-pg from converting Go zero values to SQL `NULL`. +- UpdateNotNull is renamed to UpdateNotZero. As previously it omits zero Go values, but it does not + take in account if field is nullable or not. +- ORM supports DistinctOn. +- Hooks accept and return context. +- Client respects Context.Deadline when setting net.Conn deadline. +- Client listens on Context.Done while waiting for a connection from the pool and returns an error + when context is cancelled. +- `Query.Column` does not accept relation name any more. Use `Query.Relation` instead which returns + an error if relation does not exist. +- urlvalues package is removed in favor of https://github.com/go-pg/urlstruct. You can also use + struct based filters via `Query.WhereStruct`. +- `NewModel` and `AddModel` methods of `HooklessModel` interface were renamed to `NextColumnScanner` + and `AddColumnScanner` respectively. +- `types.F` and `pg.F` are deprecated in favor of `pg.Ident`. +- `types.Q` is deprecated in favor of `pg.Safe`. +- `pg.Q` is deprecated in favor of `pg.SafeQuery`. +- `TableName` field is deprecated in favor of `tableName`. +- Always use `pg:"..."` struct field tag instead of `sql:"..."`. +- `pg:",override"` is deprecated in favor of `pg:",inherit"`. + +## v8 + +- Added `QueryContext`, `ExecContext`, and `ModelContext` which accept `context.Context`. Queries + are cancelled when context is cancelled. +- Model hooks are changed to accept `context.Context` as first argument. +- Fixed array and hstore parsers to handle multiple single quotes (#1235). + +## v7 + +- DB.OnQueryProcessed is replaced with DB.AddQueryHook. +- Added WhereStruct. +- orm.Pager is moved to urlvalues.Pager. Pager.FromURLValues returns an error if page or limit + params can't be parsed. + +## v6.16 + +- Read buffer is re-worked. Default read buffer is increased to 65kb. + +## v6.15 + +- Added Options.MinIdleConns. +- Options.MaxAge renamed to Options.MaxConnAge. +- PoolStats.FreeConns is renamed to PoolStats.IdleConns. +- New hook BeforeSelectQuery. +- `,override` is renamed to `,inherit`. +- Dialer.KeepAlive is set to 5 minutes by default. +- Added support "scram-sha-256" authentication. + +## v6.14 + +- Fields ignored with `sql:"-"` tag are no longer considered by ORM relation detector. + +## v6.12 + +- `Insert`, `Update`, and `Delete` can return `pg.ErrNoRows` and `pg.ErrMultiRows` when `Returning` + is used and model expects single row. + +## v6.11 + +- `db.Model(&strct).Update()` and `db.Model(&strct).Delete()` no longer adds WHERE condition based + on primary key when there are no conditions. Instead you should use `db.Update(&strct)` or + `db.Model(&strct).WherePK().Update()`. + +## v6.10 + +- `?Columns` is renamed to `?TableColumns`. `?Columns` is changed to produce column names without + table alias. + +## v6.9 + +- `pg:"fk"` tag now accepts SQL names instead of Go names, e.g. `pg:"fk:ParentId"` becomes + `pg:"fk:parent_id"`. Old code should continue working in most cases, but it is strongly advised to + start using new convention. +- uint and uint64 SQL type is changed from decimal to bigint according to the lesser of two evils + principle. Use `sql:"type:decimal"` to get old behavior. + +## v6.8 + +- `CreateTable` no longer adds ON DELETE hook by default. To get old behavior users should add + `sql:"on_delete:CASCADE"` tag on foreign key field. + +## v6 + +- `types.Result` is renamed to `orm.Result`. +- Added `OnQueryProcessed` event that can be used to log / report queries timing. Query logger is + removed. +- `orm.URLValues` is renamed to `orm.URLFilters`. It no longer adds ORDER clause. +- `orm.Pager` is renamed to `orm.Pagination`. +- Support for net.IP and net.IPNet. +- Support for context.Context. +- Bulk/multi updates. +- Query.WhereGroup for enclosing conditions in parentheses. + +## v5 + +- All fields are nullable by default. `,null` tag is replaced with `,notnull`. +- `Result.Affected` renamed to `Result.RowsAffected`. +- Added `Result.RowsReturned`. +- `Create` renamed to `Insert`, `BeforeCreate` to `BeforeInsert`, `AfterCreate` to `AfterInsert`. +- Indexed placeholders support, e.g. `db.Exec("SELECT ?0 + ?0", 1)`. +- Named placeholders are evaluated when query is executed. +- Added Update and Delete hooks. +- Order reworked to quote column names. OrderExpr added to bypass Order quoting restrictions. +- Group reworked to quote column names. GroupExpr added to bypass Group quoting restrictions. + +## v4 + +- `Options.Host` and `Options.Port` merged into `Options.Addr`. +- Added `Options.MaxRetries`. Now queries are not retried by default. +- `LoadInto` renamed to `Scan`, `ColumnLoader` renamed to `ColumnScanner`, LoadColumn renamed to + ScanColumn, `NewRecord() interface{}` changed to `NewModel() ColumnScanner`, + `AppendQuery(dst []byte) []byte` changed to `AppendValue(dst []byte, quote bool) ([]byte, error)`. +- Structs, maps and slices are marshalled to JSON by default. +- Added support for scanning slices, .e.g. scanning `[]int`. +- Added object relational mapping. diff --git a/vendor/github.com/go-pg/pg/LICENSE b/vendor/github.com/go-pg/pg/v10/LICENSE similarity index 100% rename from vendor/github.com/go-pg/pg/LICENSE rename to vendor/github.com/go-pg/pg/v10/LICENSE diff --git a/vendor/github.com/go-pg/pg/v10/Makefile b/vendor/github.com/go-pg/pg/v10/Makefile new file mode 100644 index 000000000..632b78281 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/Makefile @@ -0,0 +1,32 @@ +PACKAGE_DIRS := $(shell find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | sort) + +all: + TZ= go test ./... + TZ= go test ./... -short -race + TZ= go test ./... -run=NONE -bench=. -benchmem + env GOOS=linux GOARCH=386 go test ./... + go vet + golangci-lint run + +.PHONY: test +test: + TZ= PGSSLMODE=disable go test ./... -v -race + +tag: + git tag $(VERSION) + git tag extra/pgdebug/$(VERSION) + git tag extra/pgotel/$(VERSION) + git tag extra/pgsegment/$(VERSION) + +fmt: + gofmt -w -s ./ + goimports -w -local github.com/go-pg/pg ./ + +go_mod_tidy: + go get -u && go mod tidy + set -e; for dir in $(PACKAGE_DIRS); do \ + echo "go mod tidy in $${dir}"; \ + (cd "$${dir}" && \ + go get -u && \ + go mod tidy); \ + done diff --git a/vendor/github.com/go-pg/pg/v10/README.md b/vendor/github.com/go-pg/pg/v10/README.md new file mode 100644 index 000000000..83c241032 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/README.md @@ -0,0 +1,248 @@ +# PostgreSQL client and ORM for Golang + +## Maintenance mode + +go-pg is in a maintenance mode and only critical issues are addressed. New development happens in +[**Bun**](https://bun.uptrace.dev/guide/pg-migration.html) repo which offers similar functionality +but works with PostgreSQL, MySQL, MariaDB, and SQLite. + +## [Golang ORM](https://github.com/uptrace/bun) + +--- + +[![Build Status](https://travis-ci.org/go-pg/pg.svg?branch=v10)](https://travis-ci.org/go-pg/pg) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/go-pg/pg/v10)](https://pkg.go.dev/github.com/go-pg/pg/v10) +[![Documentation](https://img.shields.io/badge/pg-documentation-informational)](https://pg.uptrace.dev/) +[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) + +- [Documentation](https://pg.uptrace.dev) +- [Reference](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc) +- [Examples](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#pkg-examples) +- Example projects: + - [monetr](https://github.com/monetr/monetr) - budgeting application focused on planning for + recurring expenses + - [bunrouter](https://github.com/go-bun/bun-realworld-app) + - [gin](https://github.com/gogjango/gjango) + - [go-kit](https://github.com/Tsovak/rest-api-demo) + - [aah framework](https://github.com/kieusonlam/golamapi) + +## Tutorials + +- [GraphQL Tutorial on YouTube](https://www.youtube.com/playlist?list=PLzQWIQOqeUSNwXcneWYJHUREAIucJ5UZn). +- [Modern API design with Golang, PostgreSQL and Docker](https://bognov.tech/modern-api-design-with-golang-postgresql-and-docker) + +## Ecosystem + +- Migrations by [vmihailenco](https://github.com/go-pg/migrations) and + [robinjoseph08](https://github.com/robinjoseph08/go-pg-migrations). +- [Genna - cli tool for generating go-pg models](https://github.com/dizzyfool/genna). +- [bigint](https://github.com/d-fal/bigint) - big.Int type for go-pg. +- [urlstruct](https://github.com/go-pg/urlstruct) to decode `url.Values` into structs. +- [Sharding](https://github.com/go-pg/sharding). +- [go-pg-monitor](https://github.com/hypnoglow/go-pg-monitor) - Prometheus metrics based on go-pg + client stats. + +## Features + +- Basic types: integers, floats, string, bool, time.Time, net.IP, net.IPNet. +- sql.NullBool, sql.NullString, sql.NullInt64, sql.NullFloat64 and + [pg.NullTime](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#NullTime). +- [sql.Scanner](http://golang.org/pkg/database/sql/#Scanner) and + [sql/driver.Valuer](http://golang.org/pkg/database/sql/driver/#Valuer) interfaces. +- Structs, maps and arrays are marshalled as JSON by default. +- PostgreSQL multidimensional Arrays using + [array tag](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB-Model-PostgresArrayStructTag) + and [Array wrapper](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-Array). +- Hstore using + [hstore tag](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB-Model-HstoreStructTag) + and [Hstore wrapper](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-Hstore). +- [Composite types](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB-Model-CompositeType). +- All struct fields are nullable by default and zero values (empty string, 0, zero time, empty map + or slice, nil ptr) are marshalled as SQL `NULL`. `pg:",notnull"` is used to add SQL `NOT NULL` + constraint and `pg:",use_zero"` to allow Go zero values. +- [Transactions](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB-Begin). +- [Prepared statements](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB-Prepare). +- [Notifications](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-Listener) using + `LISTEN` and `NOTIFY`. +- [Copying data](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB-CopyFrom) using + `COPY FROM` and `COPY TO`. +- [Timeouts](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#Options) and canceling queries using + context.Context. +- Automatic connection pooling with + [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support. +- Queries retry on network errors. +- Working with models using + [ORM](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model) and + [SQL](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Query). +- Scanning variables using + [ORM](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-SelectSomeColumnsIntoVars) + and [SQL](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-Scan). +- [SelectOrInsert](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-InsertSelectOrInsert) + using on-conflict. +- [INSERT ... ON CONFLICT DO UPDATE](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-InsertOnConflictDoUpdate) + using ORM. +- Bulk/batch + [inserts](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-BulkInsert), + [updates](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-BulkUpdate), and + [deletes](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-BulkDelete). +- Common table expressions using + [WITH](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-SelectWith) and + [WrapWith](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-SelectWrapWith). +- [CountEstimate](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-CountEstimate) + using `EXPLAIN` to get + [estimated number of matching rows](https://wiki.postgresql.org/wiki/Count_estimate). +- ORM supports + [has one](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-HasOne), + [belongs to](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-BelongsTo), + [has many](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-HasMany), and + [many to many](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-ManyToMany) + with composite/multi-column primary keys. +- [Soft deletes](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-SoftDelete). +- [Creating tables from structs](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-CreateTable). +- [ForEach](https://pkg.go.dev/github.com/go-pg/pg/v10?tab=doc#example-DB.Model-ForEach) that calls + a function for each row returned by the query without loading all rows into the memory. + +## Installation + +go-pg supports 2 last Go versions and requires a Go version with +[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go +module: + +```shell +go mod init github.com/my/repo +``` + +And then install go-pg (note _v10_ in the import; omitting it is a popular mistake): + +```shell +go get github.com/go-pg/pg/v10 +``` + +## Quickstart + +```go +package pg_test + +import ( + "fmt" + + "github.com/go-pg/pg/v10" + "github.com/go-pg/pg/v10/orm" +) + +type User struct { + Id int64 + Name string + Emails []string +} + +func (u User) String() string { + return fmt.Sprintf("User<%d %s %v>", u.Id, u.Name, u.Emails) +} + +type Story struct { + Id int64 + Title string + AuthorId int64 + Author *User `pg:"rel:has-one"` +} + +func (s Story) String() string { + return fmt.Sprintf("Story<%d %s %s>", s.Id, s.Title, s.Author) +} + +func ExampleDB_Model() { + db := pg.Connect(&pg.Options{ + User: "postgres", + }) + defer db.Close() + + err := createSchema(db) + if err != nil { + panic(err) + } + + user1 := &User{ + Name: "admin", + Emails: []string{"admin1@admin", "admin2@admin"}, + } + _, err = db.Model(user1).Insert() + if err != nil { + panic(err) + } + + _, err = db.Model(&User{ + Name: "root", + Emails: []string{"root1@root", "root2@root"}, + }).Insert() + if err != nil { + panic(err) + } + + story1 := &Story{ + Title: "Cool story", + AuthorId: user1.Id, + } + _, err = db.Model(story1).Insert() + if err != nil { + panic(err) + } + + // Select user by primary key. + user := &User{Id: user1.Id} + err = db.Model(user).WherePK().Select() + if err != nil { + panic(err) + } + + // Select all users. + var users []User + err = db.Model(&users).Select() + if err != nil { + panic(err) + } + + // Select story and associated author in one query. + story := new(Story) + err = db.Model(story). + Relation("Author"). + Where("story.id = ?", story1.Id). + Select() + if err != nil { + panic(err) + } + + fmt.Println(user) + fmt.Println(users) + fmt.Println(story) + // Output: User<1 admin [admin1@admin admin2@admin]> + // [User<1 admin [admin1@admin admin2@admin]> User<2 root [root1@root root2@root]>] + // Story<1 Cool story User<1 admin [admin1@admin admin2@admin]>> +} + +// createSchema creates database schema for User and Story models. +func createSchema(db *pg.DB) error { + models := []interface{}{ + (*User)(nil), + (*Story)(nil), + } + + for _, model := range models { + err := db.Model(model).CreateTable(&orm.CreateTableOptions{ + Temp: true, + }) + if err != nil { + return err + } + } + return nil +} +``` + +## See also + +- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/) +- [Golang HTTP router](https://github.com/uptrace/bunrouter) +- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse) +- [Golang msgpack](https://github.com/vmihailenco/msgpack) +- [Distributed tracing tools](https://get.uptrace.dev/compare/distributed-tracing-tools.html) diff --git a/vendor/github.com/go-pg/pg/v10/base.go b/vendor/github.com/go-pg/pg/v10/base.go new file mode 100644 index 000000000..87de73a46 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/base.go @@ -0,0 +1,624 @@ +package pg + +import ( + "context" + "io" + "time" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/orm" + "github.com/go-pg/pg/v10/types" +) + +type baseDB struct { + db orm.DB + opt *Options + pool pool.Pooler + + fmter *orm.Formatter + queryHooks []QueryHook +} + +// PoolStats contains the stats of a connection pool. +type PoolStats pool.Stats + +// PoolStats returns connection pool stats. +func (db *baseDB) PoolStats() *PoolStats { + stats := db.pool.Stats() + return (*PoolStats)(stats) +} + +func (db *baseDB) clone() *baseDB { + return &baseDB{ + db: db.db, + opt: db.opt, + pool: db.pool, + + fmter: db.fmter, + queryHooks: copyQueryHooks(db.queryHooks), + } +} + +func (db *baseDB) withPool(p pool.Pooler) *baseDB { + cp := db.clone() + cp.pool = p + return cp +} + +func (db *baseDB) WithTimeout(d time.Duration) *baseDB { + newopt := *db.opt + newopt.ReadTimeout = d + newopt.WriteTimeout = d + + cp := db.clone() + cp.opt = &newopt + return cp +} + +func (db *baseDB) WithParam(param string, value interface{}) *baseDB { + cp := db.clone() + cp.fmter = db.fmter.WithParam(param, value) + return cp +} + +// Param returns value for the param. +func (db *baseDB) Param(param string) interface{} { + return db.fmter.Param(param) +} + +func (db *baseDB) retryBackoff(retry int) time.Duration { + return internal.RetryBackoff(retry, db.opt.MinRetryBackoff, db.opt.MaxRetryBackoff) +} + +func (db *baseDB) getConn(ctx context.Context) (*pool.Conn, error) { + cn, err := db.pool.Get(ctx) + if err != nil { + return nil, err + } + + if cn.Inited { + return cn, nil + } + + if err := db.initConn(ctx, cn); err != nil { + db.pool.Remove(ctx, cn, err) + // It is safe to reset StickyConnPool if conn can't be initialized. + if p, ok := db.pool.(*pool.StickyConnPool); ok { + _ = p.Reset(ctx) + } + if err := internal.Unwrap(err); err != nil { + return nil, err + } + return nil, err + } + + return cn, nil +} + +func (db *baseDB) initConn(ctx context.Context, cn *pool.Conn) error { + if cn.Inited { + return nil + } + cn.Inited = true + + if db.opt.TLSConfig != nil { + err := db.enableSSL(ctx, cn, db.opt.TLSConfig) + if err != nil { + return err + } + } + + err := db.startup(ctx, cn, db.opt.User, db.opt.Password, db.opt.Database, db.opt.ApplicationName) + if err != nil { + return err + } + + if db.opt.OnConnect != nil { + p := pool.NewSingleConnPool(db.pool, cn) + return db.opt.OnConnect(ctx, newConn(ctx, db.withPool(p))) + } + + return nil +} + +func (db *baseDB) releaseConn(ctx context.Context, cn *pool.Conn, err error) { + if bad, code := isBadConn(err, false); bad { + if code != "25P02" { // canceling statement if it is a bad conn expect 25P02 (current transaction is aborted) + err := db.cancelRequest(cn.ProcessID, cn.SecretKey) + if err != nil { + internal.Logger.Printf(ctx, "cancelRequest failed: %s", err) + } + } + db.pool.Remove(ctx, cn, err) + } else { + db.pool.Put(ctx, cn) + } +} + +func (db *baseDB) withConn( + ctx context.Context, fn func(context.Context, *pool.Conn) error, +) error { + cn, err := db.getConn(ctx) + if err != nil { + return err + } + + var fnDone chan struct{} + if ctx != nil && ctx.Done() != nil { + fnDone = make(chan struct{}) + go func() { + select { + case <-fnDone: // fn has finished, skip cancel + case <-ctx.Done(): + err := db.cancelRequest(cn.ProcessID, cn.SecretKey) + if err != nil { + internal.Logger.Printf(ctx, "cancelRequest failed: %s", err) + } + // Signal end of conn use. + fnDone <- struct{}{} + } + }() + } + + defer func() { + if fnDone == nil { + db.releaseConn(ctx, cn, err) + return + } + + select { + case <-fnDone: // wait for cancel to finish request + // Looks like the canceled connection must be always removed from the pool. + db.pool.Remove(ctx, cn, err) + case fnDone <- struct{}{}: // signal fn finish, skip cancel goroutine + db.releaseConn(ctx, cn, err) + } + }() + + err = fn(ctx, cn) + return err +} + +func (db *baseDB) shouldRetry(err error) bool { + switch err { + case io.EOF, io.ErrUnexpectedEOF: + return true + case nil, context.Canceled, context.DeadlineExceeded: + return false + } + + if pgerr, ok := err.(Error); ok { + switch pgerr.Field('C') { + case "40001", // serialization_failure + "53300", // too_many_connections + "55000": // attempted to delete invisible tuple + return true + case "57014": // statement_timeout + return db.opt.RetryStatementTimeout + default: + return false + } + } + + if _, ok := err.(timeoutError); ok { + return true + } + + return false +} + +// Close closes the database client, releasing any open resources. +// +// It is rare to Close a DB, as the DB handle is meant to be +// long-lived and shared between many goroutines. +func (db *baseDB) Close() error { + return db.pool.Close() +} + +// Exec executes a query ignoring returned rows. The params are for any +// placeholders in the query. +func (db *baseDB) Exec(query interface{}, params ...interface{}) (res Result, err error) { + return db.exec(db.db.Context(), query, params...) +} + +func (db *baseDB) ExecContext(c context.Context, query interface{}, params ...interface{}) (Result, error) { + return db.exec(c, query, params...) +} + +func (db *baseDB) exec(ctx context.Context, query interface{}, params ...interface{}) (Result, error) { + wb := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(wb) + + if err := writeQueryMsg(wb, db.fmter, query, params...); err != nil { + return nil, err + } + + ctx, evt, err := db.beforeQuery(ctx, db.db, nil, query, params, wb.Query()) + if err != nil { + return nil, err + } + + var res Result + var lastErr error + for attempt := 0; attempt <= db.opt.MaxRetries; attempt++ { + if attempt > 0 { + if err := internal.Sleep(ctx, db.retryBackoff(attempt-1)); err != nil { + return nil, err + } + } + + lastErr = db.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { + res, err = db.simpleQuery(ctx, cn, wb) + return err + }) + if !db.shouldRetry(lastErr) { + break + } + } + + if err := db.afterQuery(ctx, evt, res, lastErr); err != nil { + return nil, err + } + return res, lastErr +} + +// ExecOne acts like Exec, but query must affect only one row. It +// returns ErrNoRows error when query returns zero rows or +// ErrMultiRows when query returns multiple rows. +func (db *baseDB) ExecOne(query interface{}, params ...interface{}) (Result, error) { + return db.execOne(db.db.Context(), query, params...) +} + +func (db *baseDB) ExecOneContext(ctx context.Context, query interface{}, params ...interface{}) (Result, error) { + return db.execOne(ctx, query, params...) +} + +func (db *baseDB) execOne(c context.Context, query interface{}, params ...interface{}) (Result, error) { + res, err := db.ExecContext(c, query, params...) + if err != nil { + return nil, err + } + + if err := internal.AssertOneRow(res.RowsAffected()); err != nil { + return nil, err + } + return res, nil +} + +// Query executes a query that returns rows, typically a SELECT. +// The params are for any placeholders in the query. +func (db *baseDB) Query(model, query interface{}, params ...interface{}) (res Result, err error) { + return db.query(db.db.Context(), model, query, params...) +} + +func (db *baseDB) QueryContext(c context.Context, model, query interface{}, params ...interface{}) (Result, error) { + return db.query(c, model, query, params...) +} + +func (db *baseDB) query(ctx context.Context, model, query interface{}, params ...interface{}) (Result, error) { + wb := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(wb) + + if err := writeQueryMsg(wb, db.fmter, query, params...); err != nil { + return nil, err + } + + ctx, evt, err := db.beforeQuery(ctx, db.db, model, query, params, wb.Query()) + if err != nil { + return nil, err + } + + var res Result + var lastErr error + for attempt := 0; attempt <= db.opt.MaxRetries; attempt++ { + if attempt > 0 { + if err := internal.Sleep(ctx, db.retryBackoff(attempt-1)); err != nil { + return nil, err + } + } + + lastErr = db.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { + res, err = db.simpleQueryData(ctx, cn, model, wb) + return err + }) + if !db.shouldRetry(lastErr) { + break + } + } + + if err := db.afterQuery(ctx, evt, res, lastErr); err != nil { + return nil, err + } + return res, lastErr +} + +// QueryOne acts like Query, but query must return only one row. It +// returns ErrNoRows error when query returns zero rows or +// ErrMultiRows when query returns multiple rows. +func (db *baseDB) QueryOne(model, query interface{}, params ...interface{}) (Result, error) { + return db.queryOne(db.db.Context(), model, query, params...) +} + +func (db *baseDB) QueryOneContext( + ctx context.Context, model, query interface{}, params ...interface{}, +) (Result, error) { + return db.queryOne(ctx, model, query, params...) +} + +func (db *baseDB) queryOne(ctx context.Context, model, query interface{}, params ...interface{}) (Result, error) { + res, err := db.QueryContext(ctx, model, query, params...) + if err != nil { + return nil, err + } + + if err := internal.AssertOneRow(res.RowsAffected()); err != nil { + return nil, err + } + return res, nil +} + +// CopyFrom copies data from reader to a table. +func (db *baseDB) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (res Result, err error) { + c := db.db.Context() + err = db.withConn(c, func(c context.Context, cn *pool.Conn) error { + res, err = db.copyFrom(c, cn, r, query, params...) + return err + }) + return res, err +} + +// TODO: don't get/put conn in the pool. +func (db *baseDB) copyFrom( + ctx context.Context, cn *pool.Conn, r io.Reader, query interface{}, params ...interface{}, +) (res Result, err error) { + var evt *QueryEvent + + wb := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(wb) + + if err := writeQueryMsg(wb, db.fmter, query, params...); err != nil { + return nil, err + } + + var model interface{} + if len(params) > 0 { + model, _ = params[len(params)-1].(orm.TableModel) + } + + ctx, evt, err = db.beforeQuery(ctx, db.db, model, query, params, wb.Query()) + if err != nil { + return nil, err + } + + // Note that afterQuery uses the err. + defer func() { + if afterQueryErr := db.afterQuery(ctx, evt, res, err); afterQueryErr != nil { + err = afterQueryErr + } + }() + + err = cn.WithWriter(ctx, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + return writeQueryMsg(wb, db.fmter, query, params...) + }) + if err != nil { + return nil, err + } + + err = cn.WithReader(ctx, db.opt.ReadTimeout, readCopyInResponse) + if err != nil { + return nil, err + } + + for { + err = cn.WithWriter(ctx, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + return writeCopyData(wb, r) + }) + if err != nil { + if err == io.EOF { + break + } + return nil, err + } + } + + err = cn.WithWriter(ctx, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + writeCopyDone(wb) + return nil + }) + if err != nil { + return nil, err + } + + err = cn.WithReader(ctx, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + res, err = readReadyForQuery(rd) + return err + }) + if err != nil { + return nil, err + } + + return res, nil +} + +// CopyTo copies data from a table to writer. +func (db *baseDB) CopyTo(w io.Writer, query interface{}, params ...interface{}) (res Result, err error) { + c := db.db.Context() + err = db.withConn(c, func(c context.Context, cn *pool.Conn) error { + res, err = db.copyTo(c, cn, w, query, params...) + return err + }) + return res, err +} + +func (db *baseDB) copyTo( + ctx context.Context, cn *pool.Conn, w io.Writer, query interface{}, params ...interface{}, +) (res Result, err error) { + var evt *QueryEvent + + wb := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(wb) + + if err := writeQueryMsg(wb, db.fmter, query, params...); err != nil { + return nil, err + } + + var model interface{} + if len(params) > 0 { + model, _ = params[len(params)-1].(orm.TableModel) + } + + ctx, evt, err = db.beforeQuery(ctx, db.db, model, query, params, wb.Query()) + if err != nil { + return nil, err + } + + // Note that afterQuery uses the err. + defer func() { + if afterQueryErr := db.afterQuery(ctx, evt, res, err); afterQueryErr != nil { + err = afterQueryErr + } + }() + + err = cn.WithWriter(ctx, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + return writeQueryMsg(wb, db.fmter, query, params...) + }) + if err != nil { + return nil, err + } + + err = cn.WithReader(ctx, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + err := readCopyOutResponse(rd) + if err != nil { + return err + } + + res, err = readCopyData(rd, w) + return err + }) + if err != nil { + return nil, err + } + + return res, nil +} + +// Ping verifies a connection to the database is still alive, +// establishing a connection if necessary. +func (db *baseDB) Ping(ctx context.Context) error { + _, err := db.ExecContext(ctx, "SELECT 1") + return err +} + +// Model returns new query for the model. +func (db *baseDB) Model(model ...interface{}) *Query { + return orm.NewQuery(db.db, model...) +} + +func (db *baseDB) ModelContext(c context.Context, model ...interface{}) *Query { + return orm.NewQueryContext(c, db.db, model...) +} + +func (db *baseDB) Formatter() orm.QueryFormatter { + return db.fmter +} + +func (db *baseDB) cancelRequest(processID, secretKey int32) error { + c := context.TODO() + + cn, err := db.pool.NewConn(c) + if err != nil { + return err + } + defer func() { + _ = db.pool.CloseConn(cn) + }() + + return cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + writeCancelRequestMsg(wb, processID, secretKey) + return nil + }) +} + +func (db *baseDB) simpleQuery( + c context.Context, cn *pool.Conn, wb *pool.WriteBuffer, +) (*result, error) { + if err := cn.WriteBuffer(c, db.opt.WriteTimeout, wb); err != nil { + return nil, err + } + + var res *result + if err := cn.WithReader(c, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + var err error + res, err = readSimpleQuery(rd) + return err + }); err != nil { + return nil, err + } + + return res, nil +} + +func (db *baseDB) simpleQueryData( + c context.Context, cn *pool.Conn, model interface{}, wb *pool.WriteBuffer, +) (*result, error) { + if err := cn.WriteBuffer(c, db.opt.WriteTimeout, wb); err != nil { + return nil, err + } + + var res *result + if err := cn.WithReader(c, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + var err error + res, err = readSimpleQueryData(c, rd, model) + return err + }); err != nil { + return nil, err + } + + return res, nil +} + +// Prepare creates a prepared statement for later queries or +// executions. Multiple queries or executions may be run concurrently +// from the returned statement. +func (db *baseDB) Prepare(q string) (*Stmt, error) { + return prepareStmt(db.withPool(pool.NewStickyConnPool(db.pool)), q) +} + +func (db *baseDB) prepare( + c context.Context, cn *pool.Conn, q string, +) (string, []types.ColumnInfo, error) { + name := cn.NextID() + err := cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + writeParseDescribeSyncMsg(wb, name, q) + return nil + }) + if err != nil { + return "", nil, err + } + + var columns []types.ColumnInfo + err = cn.WithReader(c, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + columns, err = readParseDescribeSync(rd) + return err + }) + if err != nil { + return "", nil, err + } + + return name, columns, nil +} + +func (db *baseDB) closeStmt(c context.Context, cn *pool.Conn, name string) error { + err := cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + writeCloseMsg(wb, name) + writeFlushMsg(wb) + return nil + }) + if err != nil { + return err + } + + err = cn.WithReader(c, db.opt.ReadTimeout, readCloseCompleteMsg) + return err +} diff --git a/vendor/github.com/go-pg/pg/v10/db.go b/vendor/github.com/go-pg/pg/v10/db.go new file mode 100644 index 000000000..27664783b --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/db.go @@ -0,0 +1,142 @@ +package pg + +import ( + "context" + "fmt" + "time" + + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/orm" +) + +// Connect connects to a database using provided options. +// +// The returned DB is safe for concurrent use by multiple goroutines +// and maintains its own connection pool. +func Connect(opt *Options) *DB { + opt.init() + return newDB( + context.Background(), + &baseDB{ + opt: opt, + pool: newConnPool(opt), + fmter: orm.NewFormatter(), + }, + ) +} + +func newDB(ctx context.Context, baseDB *baseDB) *DB { + db := &DB{ + baseDB: baseDB.clone(), + ctx: ctx, + } + db.baseDB.db = db + return db +} + +// DB is a database handle representing a pool of zero or more +// underlying connections. It's safe for concurrent use by multiple +// goroutines. +type DB struct { + *baseDB + ctx context.Context +} + +var _ orm.DB = (*DB)(nil) + +func (db *DB) String() string { + return fmt.Sprintf("DB", db.opt.Addr, db.fmter) +} + +// Options returns read-only Options that were used to connect to the DB. +func (db *DB) Options() *Options { + return db.opt +} + +// Context returns DB context. +func (db *DB) Context() context.Context { + return db.ctx +} + +// WithContext returns a copy of the DB that uses the ctx. +func (db *DB) WithContext(ctx context.Context) *DB { + return newDB(ctx, db.baseDB) +} + +// WithTimeout returns a copy of the DB that uses d as the read/write timeout. +func (db *DB) WithTimeout(d time.Duration) *DB { + return newDB(db.ctx, db.baseDB.WithTimeout(d)) +} + +// WithParam returns a copy of the DB that replaces the param with the value +// in queries. +func (db *DB) WithParam(param string, value interface{}) *DB { + return newDB(db.ctx, db.baseDB.WithParam(param, value)) +} + +// Listen listens for notifications sent with NOTIFY command. +func (db *DB) Listen(ctx context.Context, channels ...string) *Listener { + ln := &Listener{ + db: db, + } + ln.init() + _ = ln.Listen(ctx, channels...) + return ln +} + +// Conn represents a single database connection rather than a pool of database +// connections. Prefer running queries from DB unless there is a specific +// need for a continuous single database connection. +// +// A Conn must call Close to return the connection to the database pool +// and may do so concurrently with a running query. +// +// After a call to Close, all operations on the connection fail. +type Conn struct { + *baseDB + ctx context.Context +} + +var _ orm.DB = (*Conn)(nil) + +// Conn returns a single connection from the connection pool. +// Queries run on the same Conn will be run in the same database session. +// +// Every Conn must be returned to the database pool after use by +// calling Conn.Close. +func (db *DB) Conn() *Conn { + return newConn(db.ctx, db.baseDB.withPool(pool.NewStickyConnPool(db.pool))) +} + +func newConn(ctx context.Context, baseDB *baseDB) *Conn { + conn := &Conn{ + baseDB: baseDB, + ctx: ctx, + } + conn.baseDB.db = conn + return conn +} + +// Context returns DB context. +func (db *Conn) Context() context.Context { + if db.ctx != nil { + return db.ctx + } + return context.Background() +} + +// WithContext returns a copy of the DB that uses the ctx. +func (db *Conn) WithContext(ctx context.Context) *Conn { + return newConn(ctx, db.baseDB) +} + +// WithTimeout returns a copy of the DB that uses d as the read/write timeout. +func (db *Conn) WithTimeout(d time.Duration) *Conn { + return newConn(db.ctx, db.baseDB.WithTimeout(d)) +} + +// WithParam returns a copy of the DB that replaces the param with the value +// in queries. +func (db *Conn) WithParam(param string, value interface{}) *Conn { + return newConn(db.ctx, db.baseDB.WithParam(param, value)) +} diff --git a/vendor/github.com/go-pg/pg/v10/doc.go b/vendor/github.com/go-pg/pg/v10/doc.go new file mode 100644 index 000000000..9a077a8c1 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/doc.go @@ -0,0 +1,4 @@ +/* +pg provides PostgreSQL client. +*/ +package pg diff --git a/vendor/github.com/go-pg/pg/error.go b/vendor/github.com/go-pg/pg/v10/error.go similarity index 58% rename from vendor/github.com/go-pg/pg/error.go rename to vendor/github.com/go-pg/pg/v10/error.go index 995207608..e47422de7 100644 --- a/vendor/github.com/go-pg/pg/error.go +++ b/vendor/github.com/go-pg/pg/v10/error.go @@ -1,10 +1,9 @@ package pg import ( - "io" "net" - "github.com/go-pg/pg/internal" + "github.com/go-pg/pg/v10/internal" ) // ErrNoRows is returned by QueryOne and ExecOne when query returned zero rows @@ -20,10 +19,12 @@ var ErrMultiRows = internal.ErrMultiRows // // https://www.postgresql.org/docs/10/static/protocol-message-formats.html type Error interface { - // Field returns a string value associated with an error code. + error + + // Field returns a string value associated with an error field. // // https://www.postgresql.org/docs/10/static/protocol-error-fields.html - Field(byte) string + Field(field byte) string // IntegrityViolation reports whether an error is a part of // Integrity Constraint Violation class of errors. @@ -34,28 +35,36 @@ type Error interface { var _ Error = (*internal.PGError)(nil) -func isBadConn(err error, allowTimeout bool) bool { +func isBadConn(err error, allowTimeout bool) (bool, string) { if err == nil { - return false + return false, "" } if _, ok := err.(internal.Error); ok { - return false + return false, "" } - if pgErr, ok := err.(Error); ok && pgErr.Field('S') != "FATAL" { - return false + if pgErr, ok := err.(Error); ok { + switch pgErr.Field('V') { + case "FATAL", "PANIC": + return true, "" + } + switch pgErr.Field('C') { + case "25P02": // current transaction is aborted + return true, "25P02" + case "57014": // canceling statement due to user request + return true, "57014" + } + return false, "" } if allowTimeout { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - return false + return !netErr.Temporary(), "" } } - return true + return true, "" } -func isNetworkError(err error) bool { - if err == io.EOF { - return true - } - _, ok := err.(net.Error) - return ok +//------------------------------------------------------------------------------ + +type timeoutError interface { + Timeout() bool } diff --git a/vendor/github.com/go-pg/pg/v10/hook.go b/vendor/github.com/go-pg/pg/v10/hook.go new file mode 100644 index 000000000..a95dc20bc --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/hook.go @@ -0,0 +1,139 @@ +package pg + +import ( + "context" + "fmt" + "time" + + "github.com/go-pg/pg/v10/orm" +) + +type ( + BeforeScanHook = orm.BeforeScanHook + AfterScanHook = orm.AfterScanHook + AfterSelectHook = orm.AfterSelectHook + BeforeInsertHook = orm.BeforeInsertHook + AfterInsertHook = orm.AfterInsertHook + BeforeUpdateHook = orm.BeforeUpdateHook + AfterUpdateHook = orm.AfterUpdateHook + BeforeDeleteHook = orm.BeforeDeleteHook + AfterDeleteHook = orm.AfterDeleteHook +) + +//------------------------------------------------------------------------------ + +type dummyFormatter struct{} + +func (dummyFormatter) FormatQuery(b []byte, query string, params ...interface{}) []byte { + return append(b, query...) +} + +// QueryEvent ... +type QueryEvent struct { + StartTime time.Time + DB orm.DB + Model interface{} + Query interface{} + Params []interface{} + fmtedQuery []byte + Result Result + Err error + + Stash map[interface{}]interface{} +} + +// QueryHook ... +type QueryHook interface { + BeforeQuery(context.Context, *QueryEvent) (context.Context, error) + AfterQuery(context.Context, *QueryEvent) error +} + +// UnformattedQuery returns the unformatted query of a query event. +// The query is only valid until the query Result is returned to the user. +func (e *QueryEvent) UnformattedQuery() ([]byte, error) { + return queryString(e.Query) +} + +func queryString(query interface{}) ([]byte, error) { + switch query := query.(type) { + case orm.TemplateAppender: + return query.AppendTemplate(nil) + case string: + return dummyFormatter{}.FormatQuery(nil, query), nil + default: + return nil, fmt.Errorf("pg: can't append %T", query) + } +} + +// FormattedQuery returns the formatted query of a query event. +// The query is only valid until the query Result is returned to the user. +func (e *QueryEvent) FormattedQuery() ([]byte, error) { + return e.fmtedQuery, nil +} + +// AddQueryHook adds a hook into query processing. +func (db *baseDB) AddQueryHook(hook QueryHook) { + db.queryHooks = append(db.queryHooks, hook) +} + +func (db *baseDB) beforeQuery( + ctx context.Context, + ormDB orm.DB, + model, query interface{}, + params []interface{}, + fmtedQuery []byte, +) (context.Context, *QueryEvent, error) { + if len(db.queryHooks) == 0 { + return ctx, nil, nil + } + + event := &QueryEvent{ + StartTime: time.Now(), + DB: ormDB, + Model: model, + Query: query, + Params: params, + fmtedQuery: fmtedQuery, + } + + for i, hook := range db.queryHooks { + var err error + ctx, err = hook.BeforeQuery(ctx, event) + if err != nil { + if err := db.afterQueryFromIndex(ctx, event, i); err != nil { + return ctx, nil, err + } + return ctx, nil, err + } + } + + return ctx, event, nil +} + +func (db *baseDB) afterQuery( + ctx context.Context, + event *QueryEvent, + res Result, + err error, +) error { + if event == nil { + return nil + } + + event.Err = err + event.Result = res + return db.afterQueryFromIndex(ctx, event, len(db.queryHooks)-1) +} + +func (db *baseDB) afterQueryFromIndex(ctx context.Context, event *QueryEvent, hookIndex int) error { + for ; hookIndex >= 0; hookIndex-- { + if err := db.queryHooks[hookIndex].AfterQuery(ctx, event); err != nil { + return err + } + } + return nil +} + +func copyQueryHooks(s []QueryHook) []QueryHook { + return s[:len(s):len(s)] +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/context.go b/vendor/github.com/go-pg/pg/v10/internal/context.go new file mode 100644 index 000000000..06d20c152 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/context.go @@ -0,0 +1,26 @@ +package internal + +import ( + "context" + "time" +) + +type UndoneContext struct { + context.Context +} + +func UndoContext(ctx context.Context) UndoneContext { + return UndoneContext{Context: ctx} +} + +func (UndoneContext) Deadline() (deadline time.Time, ok bool) { + return time.Time{}, false +} + +func (UndoneContext) Done() <-chan struct{} { + return nil +} + +func (UndoneContext) Err() error { + return nil +} diff --git a/vendor/github.com/go-pg/pg/internal/error.go b/vendor/github.com/go-pg/pg/v10/internal/error.go similarity index 87% rename from vendor/github.com/go-pg/pg/internal/error.go rename to vendor/github.com/go-pg/pg/v10/internal/error.go index c6ff3d181..ae6524aeb 100644 --- a/vendor/github.com/go-pg/pg/internal/error.go +++ b/vendor/github.com/go-pg/pg/v10/internal/error.go @@ -4,8 +4,10 @@ import ( "fmt" ) -var ErrNoRows = Errorf("pg: no rows in result set") -var ErrMultiRows = Errorf("pg: multiple rows in result set") +var ( + ErrNoRows = Errorf("pg: no rows in result set") + ErrMultiRows = Errorf("pg: multiple rows in result set") +) type Error struct { s string diff --git a/vendor/github.com/go-pg/pg/v10/internal/internal.go b/vendor/github.com/go-pg/pg/v10/internal/internal.go new file mode 100644 index 000000000..bda5028c6 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/internal.go @@ -0,0 +1,27 @@ +/* +internal is a private internal package. +*/ +package internal + +import ( + "math/rand" + "time" +) + +func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration { + if retry < 0 { + panic("not reached") + } + if minBackoff == 0 { + return 0 + } + + d := minBackoff << uint(retry) + d = minBackoff + time.Duration(rand.Int63n(int64(d))) + + if d > maxBackoff || d < minBackoff { + d = maxBackoff + } + + return d +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/log.go b/vendor/github.com/go-pg/pg/v10/internal/log.go new file mode 100644 index 000000000..7ea547b10 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/log.go @@ -0,0 +1,28 @@ +package internal + +import ( + "context" + "fmt" + "log" + "os" +) + +var Warn = log.New(os.Stderr, "WARN: pg: ", log.LstdFlags) + +var Deprecated = log.New(os.Stderr, "DEPRECATED: pg: ", log.LstdFlags) + +type Logging interface { + Printf(ctx context.Context, format string, v ...interface{}) +} + +type logger struct { + log *log.Logger +} + +func (l *logger) Printf(ctx context.Context, format string, v ...interface{}) { + _ = l.log.Output(2, fmt.Sprintf(format, v...)) +} + +var Logger Logging = &logger{ + log: log.New(os.Stderr, "pg: ", log.LstdFlags|log.Lshortfile), +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/parser/parser.go b/vendor/github.com/go-pg/pg/v10/internal/parser/parser.go new file mode 100644 index 000000000..f2db676c9 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/parser/parser.go @@ -0,0 +1,141 @@ +package parser + +import ( + "bytes" + "strconv" + + "github.com/go-pg/pg/v10/internal" +) + +type Parser struct { + b []byte + i int +} + +func New(b []byte) *Parser { + return &Parser{ + b: b, + } +} + +func NewString(s string) *Parser { + return New(internal.StringToBytes(s)) +} + +func (p *Parser) Valid() bool { + return p.i < len(p.b) +} + +func (p *Parser) Bytes() []byte { + return p.b[p.i:] +} + +func (p *Parser) Read() byte { + if p.Valid() { + c := p.b[p.i] + p.Advance() + return c + } + return 0 +} + +func (p *Parser) Peek() byte { + if p.Valid() { + return p.b[p.i] + } + return 0 +} + +func (p *Parser) Advance() { + p.i++ +} + +func (p *Parser) Skip(skip byte) bool { + if p.Peek() == skip { + p.Advance() + return true + } + return false +} + +func (p *Parser) SkipBytes(skip []byte) bool { + if len(skip) > len(p.b[p.i:]) { + return false + } + if !bytes.Equal(p.b[p.i:p.i+len(skip)], skip) { + return false + } + p.i += len(skip) + return true +} + +func (p *Parser) ReadSep(sep byte) ([]byte, bool) { + ind := bytes.IndexByte(p.b[p.i:], sep) + if ind == -1 { + b := p.b[p.i:] + p.i = len(p.b) + return b, false + } + + b := p.b[p.i : p.i+ind] + p.i += ind + 1 + return b, true +} + +func (p *Parser) ReadIdentifier() (string, bool) { + if p.i < len(p.b) && p.b[p.i] == '(' { + s := p.i + 1 + if ind := bytes.IndexByte(p.b[s:], ')'); ind != -1 { + b := p.b[s : s+ind] + p.i = s + ind + 1 + return internal.BytesToString(b), false + } + } + + ind := len(p.b) - p.i + var alpha bool + for i, c := range p.b[p.i:] { + if isNum(c) { + continue + } + if isAlpha(c) || (i > 0 && alpha && c == '_') { + alpha = true + continue + } + ind = i + break + } + if ind == 0 { + return "", false + } + b := p.b[p.i : p.i+ind] + p.i += ind + return internal.BytesToString(b), !alpha +} + +func (p *Parser) ReadNumber() int { + ind := len(p.b) - p.i + for i, c := range p.b[p.i:] { + if !isNum(c) { + ind = i + break + } + } + if ind == 0 { + return 0 + } + n, err := strconv.Atoi(string(p.b[p.i : p.i+ind])) + if err != nil { + panic(err) + } + p.i += ind + return n +} + +func isNum(c byte) bool { + return c >= '0' && c <= '9' +} + +func isAlpha(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go b/vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go new file mode 100644 index 000000000..723c12b16 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go @@ -0,0 +1,65 @@ +package parser + +import ( + "fmt" + + "github.com/go-pg/pg/v10/internal/pool" +) + +type StreamingParser struct { + pool.Reader +} + +func NewStreamingParser(rd pool.Reader) StreamingParser { + return StreamingParser{ + Reader: rd, + } +} + +func (p StreamingParser) SkipByte(skip byte) error { + c, err := p.ReadByte() + if err != nil { + return err + } + if c == skip { + return nil + } + _ = p.UnreadByte() + return fmt.Errorf("got %q, wanted %q", c, skip) +} + +func (p StreamingParser) ReadSubstring(b []byte) ([]byte, error) { + c, err := p.ReadByte() + if err != nil { + return b, err + } + + for { + if c == '"' { + return b, nil + } + + next, err := p.ReadByte() + if err != nil { + return b, err + } + + if c == '\\' { + switch next { + case '\\', '"': + b = append(b, next) + c, err = p.ReadByte() + if err != nil { + return nil, err + } + default: + b = append(b, '\\') + c = next + } + continue + } + + b = append(b, c) + c = next + } +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/conn.go b/vendor/github.com/go-pg/pg/v10/internal/pool/conn.go new file mode 100644 index 000000000..91045245b --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/conn.go @@ -0,0 +1,158 @@ +package pool + +import ( + "context" + "net" + "strconv" + "sync/atomic" + "time" +) + +var noDeadline = time.Time{} + +type Conn struct { + netConn net.Conn + rd *ReaderContext + + ProcessID int32 + SecretKey int32 + lastID int64 + + createdAt time.Time + usedAt uint32 // atomic + pooled bool + Inited bool +} + +func NewConn(netConn net.Conn) *Conn { + cn := &Conn{ + createdAt: time.Now(), + } + cn.SetNetConn(netConn) + cn.SetUsedAt(time.Now()) + return cn +} + +func (cn *Conn) UsedAt() time.Time { + unix := atomic.LoadUint32(&cn.usedAt) + return time.Unix(int64(unix), 0) +} + +func (cn *Conn) SetUsedAt(tm time.Time) { + atomic.StoreUint32(&cn.usedAt, uint32(tm.Unix())) +} + +func (cn *Conn) RemoteAddr() net.Addr { + return cn.netConn.RemoteAddr() +} + +func (cn *Conn) SetNetConn(netConn net.Conn) { + cn.netConn = netConn + if cn.rd != nil { + cn.rd.Reset(netConn) + } +} + +func (cn *Conn) LockReader() { + if cn.rd != nil { + panic("not reached") + } + cn.rd = NewReaderContext() + cn.rd.Reset(cn.netConn) +} + +func (cn *Conn) NetConn() net.Conn { + return cn.netConn +} + +func (cn *Conn) NextID() string { + cn.lastID++ + return strconv.FormatInt(cn.lastID, 10) +} + +func (cn *Conn) WithReader( + ctx context.Context, timeout time.Duration, fn func(rd *ReaderContext) error, +) error { + if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil { + return err + } + + rd := cn.rd + if rd == nil { + rd = GetReaderContext() + defer PutReaderContext(rd) + + rd.Reset(cn.netConn) + } + + rd.bytesRead = 0 + + if err := fn(rd); err != nil { + return err + } + + return nil +} + +func (cn *Conn) WithWriter( + ctx context.Context, timeout time.Duration, fn func(wb *WriteBuffer) error, +) error { + wb := GetWriteBuffer() + defer PutWriteBuffer(wb) + + if err := fn(wb); err != nil { + return err + } + + return cn.writeBuffer(ctx, timeout, wb) +} + +func (cn *Conn) WriteBuffer(ctx context.Context, timeout time.Duration, wb *WriteBuffer) error { + return cn.writeBuffer(ctx, timeout, wb) +} + +func (cn *Conn) writeBuffer( + ctx context.Context, + timeout time.Duration, + wb *WriteBuffer, +) error { + if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil { + return err + } + if _, err := cn.netConn.Write(wb.Bytes); err != nil { + return err + } + return nil +} + +func (cn *Conn) Close() error { + return cn.netConn.Close() +} + +func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) time.Time { + tm := time.Now() + cn.SetUsedAt(tm) + + if timeout > 0 { + tm = tm.Add(timeout) + } + + if ctx != nil { + deadline, ok := ctx.Deadline() + if ok { + if timeout == 0 { + return deadline + } + if deadline.Before(tm) { + return deadline + } + return tm + } + } + + if timeout > 0 { + return tm + } + + return noDeadline +} diff --git a/vendor/github.com/go-pg/pg/internal/pool/pool.go b/vendor/github.com/go-pg/pg/v10/internal/pool/pool.go similarity index 75% rename from vendor/github.com/go-pg/pg/internal/pool/pool.go rename to vendor/github.com/go-pg/pg/v10/internal/pool/pool.go index 4bdd1e069..59f2c72d0 100644 --- a/vendor/github.com/go-pg/pg/internal/pool/pool.go +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/pool.go @@ -1,17 +1,20 @@ package pool import ( + "context" "errors" "net" "sync" "sync/atomic" "time" - "github.com/go-pg/pg/internal" + "github.com/go-pg/pg/v10/internal" ) -var ErrClosed = errors.New("pg: database is closed") -var ErrPoolTimeout = errors.New("pg: connection pool timeout") +var ( + ErrClosed = errors.New("pg: database is closed") + ErrPoolTimeout = errors.New("pg: connection pool timeout") +) var timers = sync.Pool{ New: func() interface{} { @@ -33,12 +36,12 @@ type Stats struct { } type Pooler interface { - NewConn() (*Conn, error) + NewConn(context.Context) (*Conn, error) CloseConn(*Conn) error - Get() (*Conn, error) - Put(*Conn) - Remove(*Conn) + Get(context.Context) (*Conn, error) + Put(context.Context, *Conn) + Remove(context.Context, *Conn, error) Len() int IdleLen() int @@ -48,7 +51,7 @@ type Pooler interface { } type Options struct { - Dialer func() (net.Conn, error) + Dialer func(context.Context) (net.Conn, error) OnClose func(*Conn) error PoolSize int @@ -64,20 +67,21 @@ type ConnPool struct { dialErrorsNum uint32 // atomic + _closed uint32 // atomic + lastDialErrorMu sync.RWMutex lastDialError error queue chan struct{} - connsMu sync.Mutex - conns []*Conn - idleConns []*Conn - poolSize int - idleConnsLen int - stats Stats - _closed uint32 // atomic + connsMu sync.Mutex + conns []*Conn + idleConns []*Conn + + poolSize int + idleConnsLen int } var _ Pooler = (*ConnPool)(nil) @@ -91,9 +95,9 @@ func NewConnPool(opt *Options) *ConnPool { idleConns: make([]*Conn, 0, opt.PoolSize), } - for i := 0; i < opt.MinIdleConns; i++ { - p.checkMinIdleConns() - } + p.connsMu.Lock() + p.checkMinIdleConns() + p.connsMu.Unlock() if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 { go p.reaper(opt.IdleCheckFrequency) @@ -106,49 +110,61 @@ func (p *ConnPool) checkMinIdleConns() { if p.opt.MinIdleConns == 0 { return } - if p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns { + for p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns { p.poolSize++ p.idleConnsLen++ - go p.addIdleConn() + go func() { + err := p.addIdleConn() + if err != nil { + p.connsMu.Lock() + p.poolSize-- + p.idleConnsLen-- + p.connsMu.Unlock() + } + }() } } -func (p *ConnPool) addIdleConn() { - cn, err := p.newConn(true) +func (p *ConnPool) addIdleConn() error { + cn, err := p.dialConn(context.TODO(), true) if err != nil { - return + return err } p.connsMu.Lock() p.conns = append(p.conns, cn) p.idleConns = append(p.idleConns, cn) p.connsMu.Unlock() + return nil } -func (p *ConnPool) NewConn() (*Conn, error) { - return p._NewConn(false) +func (p *ConnPool) NewConn(c context.Context) (*Conn, error) { + return p.newConn(c, false) } -func (p *ConnPool) _NewConn(pooled bool) (*Conn, error) { - cn, err := p.newConn(pooled) +func (p *ConnPool) newConn(c context.Context, pooled bool) (*Conn, error) { + cn, err := p.dialConn(c, pooled) if err != nil { return nil, err } p.connsMu.Lock() + p.conns = append(p.conns, cn) if pooled { - if p.poolSize < p.opt.PoolSize { - p.poolSize++ - } else { + // If pool is full remove the cn on next Put. + if p.poolSize >= p.opt.PoolSize { cn.pooled = false + } else { + p.poolSize++ } } + p.connsMu.Unlock() return cn, nil } -func (p *ConnPool) newConn(pooled bool) (*Conn, error) { +func (p *ConnPool) dialConn(c context.Context, pooled bool) (*Conn, error) { if p.closed() { return nil, ErrClosed } @@ -157,7 +173,7 @@ func (p *ConnPool) newConn(pooled bool) (*Conn, error) { return nil, p.getLastDialError() } - netConn, err := p.opt.Dialer() + netConn, err := p.opt.Dialer(c) if err != nil { p.setLastDialError(err) if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.opt.PoolSize) { @@ -177,7 +193,7 @@ func (p *ConnPool) tryDial() { return } - conn, err := p.opt.Dialer() + conn, err := p.opt.Dialer(context.TODO()) if err != nil { p.setLastDialError(err) time.Sleep(time.Second) @@ -204,12 +220,12 @@ func (p *ConnPool) getLastDialError() error { } // Get returns existed connection from the pool or creates a new one. -func (p *ConnPool) Get() (*Conn, error) { +func (p *ConnPool) Get(ctx context.Context) (*Conn, error) { if p.closed() { return nil, ErrClosed } - err := p.waitTurn() + err := p.waitTurn(ctx) if err != nil { return nil, err } @@ -234,7 +250,7 @@ func (p *ConnPool) Get() (*Conn, error) { atomic.AddUint32(&p.stats.Misses, 1) - newcn, err := p._NewConn(true) + newcn, err := p.newConn(ctx, true) if err != nil { p.freeTurn() return nil, err @@ -247,26 +263,39 @@ func (p *ConnPool) getTurn() { p.queue <- struct{}{} } -func (p *ConnPool) waitTurn() error { +func (p *ConnPool) waitTurn(c context.Context) error { + select { + case <-c.Done(): + return c.Err() + default: + } + select { case p.queue <- struct{}{}: return nil default: - timer := timers.Get().(*time.Timer) - timer.Reset(p.opt.PoolTimeout) + } - select { - case p.queue <- struct{}{}: - if !timer.Stop() { - <-timer.C - } - timers.Put(timer) - return nil - case <-timer.C: - timers.Put(timer) - atomic.AddUint32(&p.stats.Timeouts, 1) - return ErrPoolTimeout + timer := timers.Get().(*time.Timer) + timer.Reset(p.opt.PoolTimeout) + + select { + case <-c.Done(): + if !timer.Stop() { + <-timer.C } + timers.Put(timer) + return c.Err() + case p.queue <- struct{}{}: + if !timer.Stop() { + <-timer.C + } + timers.Put(timer) + return nil + case <-timer.C: + timers.Put(timer) + atomic.AddUint32(&p.stats.Timeouts, 1) + return ErrPoolTimeout } } @@ -287,9 +316,9 @@ func (p *ConnPool) popIdle() *Conn { return cn } -func (p *ConnPool) Put(cn *Conn) { +func (p *ConnPool) Put(ctx context.Context, cn *Conn) { if !cn.pooled { - p.Remove(cn) + p.Remove(ctx, cn, nil) return } @@ -300,19 +329,24 @@ func (p *ConnPool) Put(cn *Conn) { p.freeTurn() } -func (p *ConnPool) Remove(cn *Conn) { - p.removeConn(cn) +func (p *ConnPool) Remove(ctx context.Context, cn *Conn, reason error) { + p.removeConnWithLock(cn) p.freeTurn() _ = p.closeConn(cn) } func (p *ConnPool) CloseConn(cn *Conn) error { - p.removeConn(cn) + p.removeConnWithLock(cn) return p.closeConn(cn) } -func (p *ConnPool) removeConn(cn *Conn) { +func (p *ConnPool) removeConnWithLock(cn *Conn) { p.connsMu.Lock() + p.removeConn(cn) + p.connsMu.Unlock() +} + +func (p *ConnPool) removeConn(cn *Conn) { for i, c := range p.conns { if c == cn { p.conns = append(p.conns[:i], p.conns[i+1:]...) @@ -320,10 +354,9 @@ func (p *ConnPool) removeConn(cn *Conn) { p.poolSize-- p.checkMinIdleConns() } - break + return } } - p.connsMu.Unlock() } func (p *ConnPool) closeConn(cn *Conn) error { @@ -401,20 +434,21 @@ func (p *ConnPool) Close() error { return firstErr } -func (p *ConnPool) reapStaleConn() *Conn { - if len(p.idleConns) == 0 { - return nil - } +func (p *ConnPool) reaper(frequency time.Duration) { + ticker := time.NewTicker(frequency) + defer ticker.Stop() - cn := p.idleConns[0] - if !p.isStaleConn(cn) { - return nil + for range ticker.C { + if p.closed() { + break + } + n, err := p.ReapStaleConns() + if err != nil { + internal.Logger.Printf(context.TODO(), "ReapStaleConns failed: %s", err) + continue + } + atomic.AddUint32(&p.stats.StaleConns, uint32(n)) } - - p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...) - p.idleConnsLen-- - - return cn } func (p *ConnPool) ReapStaleConns() (int, error) { @@ -426,14 +460,10 @@ func (p *ConnPool) ReapStaleConns() (int, error) { cn := p.reapStaleConn() p.connsMu.Unlock() - if cn != nil { - p.removeConn(cn) - } - p.freeTurn() if cn != nil { - p.closeConn(cn) + _ = p.closeConn(cn) n++ } else { break @@ -442,21 +472,21 @@ func (p *ConnPool) ReapStaleConns() (int, error) { return n, nil } -func (p *ConnPool) reaper(frequency time.Duration) { - ticker := time.NewTicker(frequency) - defer ticker.Stop() +func (p *ConnPool) reapStaleConn() *Conn { + if len(p.idleConns) == 0 { + return nil + } - for range ticker.C { - if p.closed() { - break - } - n, err := p.ReapStaleConns() - if err != nil { - internal.Logf("ReapStaleConns failed: %s", err) - continue - } - atomic.AddUint32(&p.stats.StaleConns, uint32(n)) + cn := p.idleConns[0] + if !p.isStaleConn(cn) { + return nil } + + p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...) + p.idleConnsLen-- + p.removeConn(cn) + + return cn } func (p *ConnPool) isStaleConn(cn *Conn) bool { @@ -468,7 +498,7 @@ func (p *ConnPool) isStaleConn(cn *Conn) bool { if p.opt.IdleTimeout > 0 && now.Sub(cn.UsedAt()) >= p.opt.IdleTimeout { return true } - if p.opt.MaxConnAge > 0 && now.Sub(cn.InitedAt) >= p.opt.MaxConnAge { + if p.opt.MaxConnAge > 0 && now.Sub(cn.createdAt) >= p.opt.MaxConnAge { return true } diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go new file mode 100644 index 000000000..6c0cdffa2 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go @@ -0,0 +1,63 @@ +package pool + +import "context" + +type SingleConnPool struct { + pool Pooler + cn *Conn + stickyErr error +} + +var _ Pooler = (*SingleConnPool)(nil) + +func NewSingleConnPool(pool Pooler, cn *Conn) *SingleConnPool { + return &SingleConnPool{ + pool: pool, + cn: cn, + } +} + +func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) { + return p.pool.NewConn(ctx) +} + +func (p *SingleConnPool) CloseConn(cn *Conn) error { + return p.pool.CloseConn(cn) +} + +func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) { + if p.stickyErr != nil { + return nil, p.stickyErr + } + return p.cn, nil +} + +func (p *SingleConnPool) Put(ctx context.Context, cn *Conn) {} + +func (p *SingleConnPool) Remove(ctx context.Context, cn *Conn, reason error) { + p.cn = nil + p.stickyErr = reason + // If ctx is cancelled without a reason(error) value, + // then the ctx.Error is used as the reason for why the p.cn is assigned nil. + if reason == nil && ctx != nil { + p.stickyErr = ctx.Err() + } +} + +func (p *SingleConnPool) Close() error { + p.cn = nil + p.stickyErr = ErrClosed + return nil +} + +func (p *SingleConnPool) Len() int { + return 0 +} + +func (p *SingleConnPool) IdleLen() int { + return 0 +} + +func (p *SingleConnPool) Stats() *Stats { + return &Stats{} +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go new file mode 100644 index 000000000..0415b5e87 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go @@ -0,0 +1,202 @@ +package pool + +import ( + "context" + "errors" + "fmt" + "sync/atomic" +) + +const ( + stateDefault = 0 + stateInited = 1 + stateClosed = 2 +) + +type BadConnError struct { + wrapped error +} + +var _ error = (*BadConnError)(nil) + +func (e BadConnError) Error() string { + s := "pg: Conn is in a bad state" + if e.wrapped != nil { + s += ": " + e.wrapped.Error() + } + return s +} + +func (e BadConnError) Unwrap() error { + return e.wrapped +} + +//------------------------------------------------------------------------------ + +type StickyConnPool struct { + pool Pooler + shared int32 // atomic + + state uint32 // atomic + ch chan *Conn + + _badConnError atomic.Value +} + +var _ Pooler = (*StickyConnPool)(nil) + +func NewStickyConnPool(pool Pooler) *StickyConnPool { + p, ok := pool.(*StickyConnPool) + if !ok { + p = &StickyConnPool{ + pool: pool, + ch: make(chan *Conn, 1), + } + } + atomic.AddInt32(&p.shared, 1) + return p +} + +func (p *StickyConnPool) NewConn(ctx context.Context) (*Conn, error) { + return p.pool.NewConn(ctx) +} + +func (p *StickyConnPool) CloseConn(cn *Conn) error { + return p.pool.CloseConn(cn) +} + +func (p *StickyConnPool) Get(ctx context.Context) (*Conn, error) { + // In worst case this races with Close which is not a very common operation. + for i := 0; i < 1000; i++ { + switch atomic.LoadUint32(&p.state) { + case stateDefault: + cn, err := p.pool.Get(ctx) + if err != nil { + return nil, err + } + if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) { + return cn, nil + } + p.pool.Remove(ctx, cn, ErrClosed) + case stateInited: + if err := p.badConnError(); err != nil { + return nil, err + } + cn, ok := <-p.ch + if !ok { + return nil, ErrClosed + } + return cn, nil + case stateClosed: + return nil, ErrClosed + default: + panic("not reached") + } + } + return nil, fmt.Errorf("pg: StickyConnPool.Get: infinite loop") +} + +func (p *StickyConnPool) Put(ctx context.Context, cn *Conn) { + defer func() { + if recover() != nil { + p.freeConn(ctx, cn) + } + }() + p.ch <- cn +} + +func (p *StickyConnPool) freeConn(ctx context.Context, cn *Conn) { + if err := p.badConnError(); err != nil { + p.pool.Remove(ctx, cn, err) + } else { + p.pool.Put(ctx, cn) + } +} + +func (p *StickyConnPool) Remove(ctx context.Context, cn *Conn, reason error) { + defer func() { + if recover() != nil { + p.pool.Remove(ctx, cn, ErrClosed) + } + }() + p._badConnError.Store(BadConnError{wrapped: reason}) + p.ch <- cn +} + +func (p *StickyConnPool) Close() error { + if shared := atomic.AddInt32(&p.shared, -1); shared > 0 { + return nil + } + + for i := 0; i < 1000; i++ { + state := atomic.LoadUint32(&p.state) + if state == stateClosed { + return ErrClosed + } + if atomic.CompareAndSwapUint32(&p.state, state, stateClosed) { + close(p.ch) + cn, ok := <-p.ch + if ok { + p.freeConn(context.TODO(), cn) + } + return nil + } + } + + return errors.New("pg: StickyConnPool.Close: infinite loop") +} + +func (p *StickyConnPool) Reset(ctx context.Context) error { + if p.badConnError() == nil { + return nil + } + + select { + case cn, ok := <-p.ch: + if !ok { + return ErrClosed + } + p.pool.Remove(ctx, cn, ErrClosed) + p._badConnError.Store(BadConnError{wrapped: nil}) + default: + return errors.New("pg: StickyConnPool does not have a Conn") + } + + if !atomic.CompareAndSwapUint32(&p.state, stateInited, stateDefault) { + state := atomic.LoadUint32(&p.state) + return fmt.Errorf("pg: invalid StickyConnPool state: %d", state) + } + + return nil +} + +func (p *StickyConnPool) badConnError() error { + if v := p._badConnError.Load(); v != nil { + err := v.(BadConnError) + if err.wrapped != nil { + return err + } + } + return nil +} + +func (p *StickyConnPool) Len() int { + switch atomic.LoadUint32(&p.state) { + case stateDefault: + return 0 + case stateInited: + return 1 + case stateClosed: + return 0 + default: + panic("not reached") + } +} + +func (p *StickyConnPool) IdleLen() int { + return len(p.ch) +} + +func (p *StickyConnPool) Stats() *Stats { + return &Stats{} +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/reader.go b/vendor/github.com/go-pg/pg/v10/internal/pool/reader.go new file mode 100644 index 000000000..b5d00807d --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/reader.go @@ -0,0 +1,80 @@ +package pool + +import ( + "sync" +) + +type Reader interface { + Buffered() int + + Bytes() []byte + Read([]byte) (int, error) + ReadByte() (byte, error) + UnreadByte() error + ReadSlice(byte) ([]byte, error) + Discard(int) (int, error) + + // ReadBytes(fn func(byte) bool) ([]byte, error) + // ReadN(int) ([]byte, error) + ReadFull() ([]byte, error) + ReadFullTemp() ([]byte, error) +} + +type ColumnInfo struct { + Index int16 + DataType int32 + Name string +} + +type ColumnAlloc struct { + columns []ColumnInfo +} + +func NewColumnAlloc() *ColumnAlloc { + return new(ColumnAlloc) +} + +func (c *ColumnAlloc) Reset() { + c.columns = c.columns[:0] +} + +func (c *ColumnAlloc) New(index int16, name []byte) *ColumnInfo { + c.columns = append(c.columns, ColumnInfo{ + Index: index, + Name: string(name), + }) + return &c.columns[len(c.columns)-1] +} + +func (c *ColumnAlloc) Columns() []ColumnInfo { + return c.columns +} + +type ReaderContext struct { + *BufReader + ColumnAlloc *ColumnAlloc +} + +func NewReaderContext() *ReaderContext { + const bufSize = 1 << 20 // 1mb + return &ReaderContext{ + BufReader: NewBufReader(bufSize), + ColumnAlloc: NewColumnAlloc(), + } +} + +var readerPool = sync.Pool{ + New: func() interface{} { + return NewReaderContext() + }, +} + +func GetReaderContext() *ReaderContext { + rd := readerPool.Get().(*ReaderContext) + return rd +} + +func PutReaderContext(rd *ReaderContext) { + rd.ColumnAlloc.Reset() + readerPool.Put(rd) +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go new file mode 100644 index 000000000..3172e8b05 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go @@ -0,0 +1,431 @@ +// Copyright 2009 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 pool + +import ( + "bufio" + "bytes" + "io" +) + +type BufReader struct { + rd io.Reader // reader provided by the client + + buf []byte + r, w int // buf read and write positions + lastByte int + bytesRead int64 + err error + + available int // bytes available for reading + brd BytesReader // reusable bytes reader +} + +func NewBufReader(bufSize int) *BufReader { + return &BufReader{ + buf: make([]byte, bufSize), + available: -1, + } +} + +func (b *BufReader) BytesReader(n int) *BytesReader { + if n == -1 { + n = 0 + } + buf := b.buf[b.r : b.r+n] + b.r += n + b.brd.Reset(buf) + return &b.brd +} + +func (b *BufReader) SetAvailable(n int) { + b.available = n +} + +func (b *BufReader) Available() int { + return b.available +} + +func (b *BufReader) changeAvailable(n int) { + if b.available != -1 { + b.available += n + } +} + +func (b *BufReader) Reset(rd io.Reader) { + b.rd = rd + b.r, b.w = 0, 0 + b.err = nil +} + +// Buffered returns the number of bytes that can be read from the current buffer. +func (b *BufReader) Buffered() int { + buffered := b.w - b.r + if b.available == -1 || buffered <= b.available { + return buffered + } + return b.available +} + +func (b *BufReader) Bytes() []byte { + if b.available == -1 { + return b.buf[b.r:b.w] + } + w := b.r + b.available + if w > b.w { + w = b.w + } + return b.buf[b.r:w] +} + +func (b *BufReader) flush() []byte { + if b.available == -1 { + buf := b.buf[b.r:b.w] + b.r = b.w + return buf + } + + w := b.r + b.available + if w > b.w { + w = b.w + } + buf := b.buf[b.r:w] + b.r = w + b.changeAvailable(-len(buf)) + return buf +} + +// fill reads a new chunk into the buffer. +func (b *BufReader) fill() { + // Slide existing data to beginning. + if b.r > 0 { + copy(b.buf, b.buf[b.r:b.w]) + b.w -= b.r + b.r = 0 + } + + if b.w >= len(b.buf) { + panic("bufio: tried to fill full buffer") + } + if b.available == 0 { + b.err = io.EOF + return + } + + // Read new data: try a limited number of times. + const maxConsecutiveEmptyReads = 100 + for i := maxConsecutiveEmptyReads; i > 0; i-- { + n, err := b.read(b.buf[b.w:]) + b.w += n + if err != nil { + b.err = err + return + } + if n > 0 { + return + } + } + b.err = io.ErrNoProgress +} + +func (b *BufReader) readErr() error { + err := b.err + b.err = nil + return err +} + +func (b *BufReader) Read(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, b.readErr() + } + + if b.available != -1 { + if b.available == 0 { + return 0, io.EOF + } + if len(p) > b.available { + p = p[:b.available] + } + } + + if b.r == b.w { + if b.err != nil { + return 0, b.readErr() + } + + if len(p) >= len(b.buf) { + // Large read, empty buffer. + // Read directly into p to avoid copy. + n, err = b.read(p) + if n > 0 { + b.changeAvailable(-n) + b.lastByte = int(p[n-1]) + } + return n, err + } + + // One read. + // Do not use b.fill, which will loop. + b.r = 0 + b.w = 0 + n, b.err = b.read(b.buf) + if n == 0 { + return 0, b.readErr() + } + b.w += n + } + + // copy as much as we can + n = copy(p, b.Bytes()) + b.r += n + b.changeAvailable(-n) + b.lastByte = int(b.buf[b.r-1]) + return n, nil +} + +// ReadSlice reads until the first occurrence of delim in the input, +// returning a slice pointing at the bytes in the buffer. +// The bytes stop being valid at the next read. +// If ReadSlice encounters an error before finding a delimiter, +// it returns all the data in the buffer and the error itself (often io.EOF). +// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim. +// Because the data returned from ReadSlice will be overwritten +// by the next I/O operation, most clients should use +// ReadBytes or ReadString instead. +// ReadSlice returns err != nil if and only if line does not end in delim. +func (b *BufReader) ReadSlice(delim byte) (line []byte, err error) { + for { + // Search buffer. + if i := bytes.IndexByte(b.Bytes(), delim); i >= 0 { + i++ + line = b.buf[b.r : b.r+i] + b.r += i + b.changeAvailable(-i) + break + } + + // Pending error? + if b.err != nil { + line = b.flush() + err = b.readErr() + break + } + + buffered := b.Buffered() + + // Out of available. + if b.available != -1 && buffered >= b.available { + line = b.flush() + err = io.EOF + break + } + + // Buffer full? + if buffered >= len(b.buf) { + line = b.flush() + err = bufio.ErrBufferFull + break + } + + b.fill() // buffer is not full + } + + // Handle last byte, if any. + if i := len(line) - 1; i >= 0 { + b.lastByte = int(line[i]) + } + + return line, err +} + +func (b *BufReader) ReadBytes(fn func(byte) bool) (line []byte, err error) { + for { + for i, c := range b.Bytes() { + if !fn(c) { + i-- + line = b.buf[b.r : b.r+i] //nolint + b.r += i + b.changeAvailable(-i) + break + } + } + + // Pending error? + if b.err != nil { + line = b.flush() + err = b.readErr() + break + } + + buffered := b.Buffered() + + // Out of available. + if b.available != -1 && buffered >= b.available { + line = b.flush() + err = io.EOF + break + } + + // Buffer full? + if buffered >= len(b.buf) { + line = b.flush() + err = bufio.ErrBufferFull + break + } + + b.fill() // buffer is not full + } + + // Handle last byte, if any. + if i := len(line) - 1; i >= 0 { + b.lastByte = int(line[i]) + } + + return line, err +} + +func (b *BufReader) ReadByte() (byte, error) { + if b.available == 0 { + return 0, io.EOF + } + for b.r == b.w { + if b.err != nil { + return 0, b.readErr() + } + b.fill() // buffer is empty + } + c := b.buf[b.r] + b.r++ + b.lastByte = int(c) + b.changeAvailable(-1) + return c, nil +} + +func (b *BufReader) UnreadByte() error { + if b.lastByte < 0 || b.r == 0 && b.w > 0 { + return bufio.ErrInvalidUnreadByte + } + // b.r > 0 || b.w == 0 + if b.r > 0 { + b.r-- + } else { + // b.r == 0 && b.w == 0 + b.w = 1 + } + b.buf[b.r] = byte(b.lastByte) + b.lastByte = -1 + b.changeAvailable(+1) + return nil +} + +// Discard skips the next n bytes, returning the number of bytes discarded. +// +// If Discard skips fewer than n bytes, it also returns an error. +// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without +// reading from the underlying io.BufReader. +func (b *BufReader) Discard(n int) (discarded int, err error) { + if n < 0 { + return 0, bufio.ErrNegativeCount + } + if n == 0 { + return + } + remain := n + for { + skip := b.Buffered() + if skip == 0 { + b.fill() + skip = b.Buffered() + } + if skip > remain { + skip = remain + } + b.r += skip + b.changeAvailable(-skip) + remain -= skip + if remain == 0 { + return n, nil + } + if b.err != nil { + return n - remain, b.readErr() + } + } +} + +func (b *BufReader) ReadN(n int) (line []byte, err error) { + if n < 0 { + return nil, bufio.ErrNegativeCount + } + if n == 0 { + return + } + + nn := n + if b.available != -1 && nn > b.available { + nn = b.available + } + + for { + buffered := b.Buffered() + + if buffered >= nn { + line = b.buf[b.r : b.r+nn] + b.r += nn + b.changeAvailable(-nn) + if n > nn { + err = io.EOF + } + break + } + + // Pending error? + if b.err != nil { + line = b.flush() + err = b.readErr() + break + } + + // Buffer full? + if buffered >= len(b.buf) { + line = b.flush() + err = bufio.ErrBufferFull + break + } + + b.fill() // buffer is not full + } + + // Handle last byte, if any. + if i := len(line) - 1; i >= 0 { + b.lastByte = int(line[i]) + } + + return line, err +} + +func (b *BufReader) ReadFull() ([]byte, error) { + if b.available == -1 { + panic("not reached") + } + buf := make([]byte, b.available) + _, err := io.ReadFull(b, buf) + return buf, err +} + +func (b *BufReader) ReadFullTemp() ([]byte, error) { + if b.available == -1 { + panic("not reached") + } + if b.available <= len(b.buf) { + return b.ReadN(b.available) + } + return b.ReadFull() +} + +func (b *BufReader) read(buf []byte) (int, error) { + n, err := b.rd.Read(buf) + b.bytesRead += int64(n) + return n, err +} diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go new file mode 100644 index 000000000..93646b1da --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go @@ -0,0 +1,121 @@ +// 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. + +package pool + +import ( + "bytes" + "errors" + "io" +) + +type BytesReader struct { + s []byte + i int +} + +func NewBytesReader(b []byte) *BytesReader { + return &BytesReader{ + s: b, + } +} + +func (r *BytesReader) Reset(b []byte) { + r.s = b + r.i = 0 +} + +func (r *BytesReader) Buffered() int { + return len(r.s) - r.i +} + +func (r *BytesReader) Bytes() []byte { + return r.s[r.i:] +} + +func (r *BytesReader) Read(b []byte) (n int, err error) { + if r.i >= len(r.s) { + return 0, io.EOF + } + n = copy(b, r.s[r.i:]) + r.i += n + return +} + +func (r *BytesReader) ReadByte() (byte, error) { + if r.i >= len(r.s) { + return 0, io.EOF + } + b := r.s[r.i] + r.i++ + return b, nil +} + +func (r *BytesReader) UnreadByte() error { + if r.i <= 0 { + return errors.New("UnreadByte: at beginning of slice") + } + r.i-- + return nil +} + +func (r *BytesReader) ReadSlice(delim byte) ([]byte, error) { + if i := bytes.IndexByte(r.s[r.i:], delim); i >= 0 { + i++ + line := r.s[r.i : r.i+i] + r.i += i + return line, nil + } + + line := r.s[r.i:] + r.i = len(r.s) + return line, io.EOF +} + +func (r *BytesReader) ReadBytes(fn func(byte) bool) ([]byte, error) { + for i, c := range r.s[r.i:] { + if !fn(c) { + i++ + line := r.s[r.i : r.i+i] + r.i += i + return line, nil + } + } + + line := r.s[r.i:] + r.i = len(r.s) + return line, io.EOF +} + +func (r *BytesReader) Discard(n int) (int, error) { + b, err := r.ReadN(n) + return len(b), err +} + +func (r *BytesReader) ReadN(n int) ([]byte, error) { + nn := n + if nn > len(r.s) { + nn = len(r.s) + } + + b := r.s[r.i : r.i+nn] + r.i += nn + if n > nn { + return b, io.EOF + } + return b, nil +} + +func (r *BytesReader) ReadFull() ([]byte, error) { + b := make([]byte, len(r.s)-r.i) + copy(b, r.s[r.i:]) + r.i = len(r.s) + return b, nil +} + +func (r *BytesReader) ReadFullTemp() ([]byte, error) { + b := r.s[r.i:] + r.i = len(r.s) + return b, nil +} diff --git a/vendor/github.com/go-pg/pg/internal/pool/write_buffer.go b/vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go similarity index 78% rename from vendor/github.com/go-pg/pg/internal/pool/write_buffer.go rename to vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go index 71eb753c1..6981d3f4c 100644 --- a/vendor/github.com/go-pg/pg/internal/pool/write_buffer.go +++ b/vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go @@ -3,30 +3,44 @@ package pool import ( "encoding/binary" "io" + "sync" ) +const defaultBufSize = 65 << 10 // 65kb + +var wbPool = sync.Pool{ + New: func() interface{} { + return NewWriteBuffer() + }, +} + +func GetWriteBuffer() *WriteBuffer { + wb := wbPool.Get().(*WriteBuffer) + return wb +} + +func PutWriteBuffer(wb *WriteBuffer) { + wb.Reset() + wbPool.Put(wb) +} + type WriteBuffer struct { Bytes []byte - msgStart, paramStart int + msgStart int + paramStart int } func NewWriteBuffer() *WriteBuffer { - return new(WriteBuffer) -} - -func (buf *WriteBuffer) Buffer() []byte { - return buf.Bytes[:cap(buf.Bytes)] + return &WriteBuffer{ + Bytes: make([]byte, 0, defaultBufSize), + } } func (buf *WriteBuffer) Reset() { buf.Bytes = buf.Bytes[:0] } -func (buf *WriteBuffer) ResetBuffer(b []byte) { - buf.Bytes = b[:0] -} - func (buf *WriteBuffer) StartMessage(c byte) { if c == 0 { buf.msgStart = len(buf.Bytes) @@ -42,6 +56,10 @@ func (buf *WriteBuffer) FinishMessage() { buf.Bytes[buf.msgStart:], uint32(len(buf.Bytes)-buf.msgStart)) } +func (buf *WriteBuffer) Query() []byte { + return buf.Bytes[buf.msgStart+4 : len(buf.Bytes)-1] +} + func (buf *WriteBuffer) StartParam() { buf.paramStart = len(buf.Bytes) buf.Bytes = append(buf.Bytes, 0, 0, 0, 0) @@ -91,6 +109,6 @@ func (buf *WriteBuffer) WriteByte(c byte) error { func (buf *WriteBuffer) ReadFrom(r io.Reader) (int64, error) { n, err := r.Read(buf.Bytes[len(buf.Bytes):cap(buf.Bytes)]) - buf.Bytes = buf.Bytes[:len(buf.Bytes)+int(n)] + buf.Bytes = buf.Bytes[:len(buf.Bytes)+n] return int64(n), err } diff --git a/vendor/github.com/go-pg/pg/v10/internal/safe.go b/vendor/github.com/go-pg/pg/v10/internal/safe.go new file mode 100644 index 000000000..2879c5d97 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/safe.go @@ -0,0 +1,12 @@ +//go:build appengine +// +build appengine + +package internal + +func BytesToString(b []byte) string { + return string(b) +} + +func StringToBytes(s string) []byte { + return []byte(s) +} diff --git a/vendor/github.com/go-pg/pg/internal/strconv.go b/vendor/github.com/go-pg/pg/v10/internal/strconv.go similarity index 100% rename from vendor/github.com/go-pg/pg/internal/strconv.go rename to vendor/github.com/go-pg/pg/v10/internal/strconv.go diff --git a/vendor/github.com/go-pg/pg/internal/underscore.go b/vendor/github.com/go-pg/pg/v10/internal/underscore.go similarity index 100% rename from vendor/github.com/go-pg/pg/internal/underscore.go rename to vendor/github.com/go-pg/pg/v10/internal/underscore.go diff --git a/vendor/github.com/go-pg/pg/v10/internal/unsafe.go b/vendor/github.com/go-pg/pg/v10/internal/unsafe.go new file mode 100644 index 000000000..1888144a0 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/internal/unsafe.go @@ -0,0 +1,23 @@ +//go:build !appengine +// +build !appengine + +package internal + +import ( + "unsafe" +) + +// BytesToString converts byte slice to string. +func BytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// StringToBytes converts string to byte slice. +func StringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer( + &struct { + string + Cap int + }{s, len(s)}, + )) +} diff --git a/vendor/github.com/go-pg/pg/internal/util.go b/vendor/github.com/go-pg/pg/v10/internal/util.go similarity index 60% rename from vendor/github.com/go-pg/pg/internal/util.go rename to vendor/github.com/go-pg/pg/v10/internal/util.go index 12ec11923..80ad1dd9a 100644 --- a/vendor/github.com/go-pg/pg/internal/util.go +++ b/vendor/github.com/go-pg/pg/v10/internal/util.go @@ -1,8 +1,33 @@ package internal -import "reflect" +import ( + "context" + "reflect" + "time" +) + +func Sleep(ctx context.Context, dur time.Duration) error { + t := time.NewTimer(dur) + defer t.Stop() + + select { + case <-t.C: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value { + if v.Kind() == reflect.Array { + var pos int + return func() reflect.Value { + v := v.Index(pos) + pos++ + return v + } + } + elemType := v.Type().Elem() if elemType.Kind() == reflect.Ptr { @@ -34,3 +59,13 @@ func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value { return v.Index(v.Len() - 1) } } + +func Unwrap(err error) error { + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/vendor/github.com/go-pg/pg/v10/listener.go b/vendor/github.com/go-pg/pg/v10/listener.go new file mode 100644 index 000000000..4b326d8c6 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/listener.go @@ -0,0 +1,416 @@ +package pg + +import ( + "context" + "errors" + "fmt" + "strings" + "sync" + "time" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/types" +) + +const gopgChannel = "gopg:ping" + +var ( + errListenerClosed = errors.New("pg: listener is closed") + errPingTimeout = errors.New("pg: ping timeout") +) + +// Notification which is received with LISTEN command. +type Notification struct { + Channel string + Payload string +} + +// Listener listens for notifications sent with NOTIFY command. +// It's NOT safe for concurrent use by multiple goroutines +// except the Channel API. +type Listener struct { + db *DB + + channels []string + + mu sync.Mutex + cn *pool.Conn + exit chan struct{} + closed bool + + chOnce sync.Once + ch chan Notification + pingCh chan struct{} +} + +func (ln *Listener) String() string { + ln.mu.Lock() + defer ln.mu.Unlock() + + return fmt.Sprintf("Listener(%s)", strings.Join(ln.channels, ", ")) +} + +func (ln *Listener) init() { + ln.exit = make(chan struct{}) +} + +func (ln *Listener) connWithLock(ctx context.Context) (*pool.Conn, error) { + ln.mu.Lock() + cn, err := ln.conn(ctx) + ln.mu.Unlock() + + switch err { + case nil: + return cn, nil + case errListenerClosed: + return nil, err + case pool.ErrClosed: + _ = ln.Close() + return nil, errListenerClosed + default: + internal.Logger.Printf(ctx, "pg: Listen failed: %s", err) + return nil, err + } +} + +func (ln *Listener) conn(ctx context.Context) (*pool.Conn, error) { + if ln.closed { + return nil, errListenerClosed + } + + if ln.cn != nil { + return ln.cn, nil + } + + cn, err := ln.db.pool.NewConn(ctx) + if err != nil { + return nil, err + } + + if err := ln.db.initConn(ctx, cn); err != nil { + _ = ln.db.pool.CloseConn(cn) + return nil, err + } + + cn.LockReader() + + if len(ln.channels) > 0 { + err := ln.listen(ctx, cn, ln.channels...) + if err != nil { + _ = ln.db.pool.CloseConn(cn) + return nil, err + } + } + + ln.cn = cn + return cn, nil +} + +func (ln *Listener) releaseConn(ctx context.Context, cn *pool.Conn, err error, allowTimeout bool) { + ln.mu.Lock() + if ln.cn == cn { + if bad, _ := isBadConn(err, allowTimeout); bad { + ln.reconnect(ctx, err) + } + } + ln.mu.Unlock() +} + +func (ln *Listener) reconnect(ctx context.Context, reason error) { + _ = ln.closeTheCn(reason) + _, _ = ln.conn(ctx) +} + +func (ln *Listener) closeTheCn(reason error) error { + if ln.cn == nil { + return nil + } + if !ln.closed { + internal.Logger.Printf(ln.db.ctx, "pg: discarding bad listener connection: %s", reason) + } + + err := ln.db.pool.CloseConn(ln.cn) + ln.cn = nil + return err +} + +// Close closes the listener, releasing any open resources. +func (ln *Listener) Close() error { + ln.mu.Lock() + defer ln.mu.Unlock() + + if ln.closed { + return errListenerClosed + } + ln.closed = true + close(ln.exit) + + return ln.closeTheCn(errListenerClosed) +} + +// Listen starts listening for notifications on channels. +func (ln *Listener) Listen(ctx context.Context, channels ...string) error { + // Always append channels so DB.Listen works correctly. + ln.mu.Lock() + ln.channels = appendIfNotExists(ln.channels, channels...) + ln.mu.Unlock() + + cn, err := ln.connWithLock(ctx) + if err != nil { + return err + } + + if err := ln.listen(ctx, cn, channels...); err != nil { + ln.releaseConn(ctx, cn, err, false) + return err + } + + return nil +} + +func (ln *Listener) listen(ctx context.Context, cn *pool.Conn, channels ...string) error { + err := cn.WithWriter(ctx, ln.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + for _, channel := range channels { + if err := writeQueryMsg(wb, ln.db.fmter, "LISTEN ?", pgChan(channel)); err != nil { + return err + } + } + return nil + }) + return err +} + +// Unlisten stops listening for notifications on channels. +func (ln *Listener) Unlisten(ctx context.Context, channels ...string) error { + ln.mu.Lock() + ln.channels = removeIfExists(ln.channels, channels...) + + cn, err := ln.conn(ctx) + // I don't want to defer this unlock as the mutex is re-acquired in the `.releaseConn` function. But it is safe to + // unlock here regardless of an error. + ln.mu.Unlock() + if err != nil { + return err + } + + if err := ln.unlisten(ctx, cn, channels...); err != nil { + ln.releaseConn(ctx, cn, err, false) + return err + } + + return nil +} + +func (ln *Listener) unlisten(ctx context.Context, cn *pool.Conn, channels ...string) error { + err := cn.WithWriter(ctx, ln.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + for _, channel := range channels { + if err := writeQueryMsg(wb, ln.db.fmter, "UNLISTEN ?", pgChan(channel)); err != nil { + return err + } + } + return nil + }) + return err +} + +// Receive indefinitely waits for a notification. This is low-level API +// and in most cases Channel should be used instead. +func (ln *Listener) Receive(ctx context.Context) (channel string, payload string, err error) { + return ln.ReceiveTimeout(ctx, 0) +} + +// ReceiveTimeout waits for a notification until timeout is reached. +// This is low-level API and in most cases Channel should be used instead. +func (ln *Listener) ReceiveTimeout( + ctx context.Context, timeout time.Duration, +) (channel, payload string, err error) { + cn, err := ln.connWithLock(ctx) + if err != nil { + return "", "", err + } + + err = cn.WithReader(ctx, timeout, func(rd *pool.ReaderContext) error { + channel, payload, err = readNotification(rd) + return err + }) + if err != nil { + ln.releaseConn(ctx, cn, err, timeout > 0) + return "", "", err + } + + return channel, payload, nil +} + +// Channel returns a channel for concurrently receiving notifications. +// It periodically sends Ping notification to test connection health. +// +// The channel is closed with Listener. Receive* APIs can not be used +// after channel is created. +func (ln *Listener) Channel() <-chan Notification { + return ln.channel(100) +} + +// ChannelSize is like Channel, but creates a Go channel +// with specified buffer size. +func (ln *Listener) ChannelSize(size int) <-chan Notification { + return ln.channel(size) +} + +func (ln *Listener) channel(size int) <-chan Notification { + ln.chOnce.Do(func() { + ln.initChannel(size) + }) + if cap(ln.ch) != size { + err := fmt.Errorf("pg: Listener.Channel is called with different buffer size") + panic(err) + } + return ln.ch +} + +func (ln *Listener) initChannel(size int) { + const pingTimeout = time.Second + const chanSendTimeout = time.Minute + + ctx := ln.db.ctx + _ = ln.Listen(ctx, gopgChannel) + + ln.ch = make(chan Notification, size) + ln.pingCh = make(chan struct{}, 1) + + go func() { + timer := time.NewTimer(time.Minute) + timer.Stop() + + var errCount int + for { + channel, payload, err := ln.Receive(ctx) + if err != nil { + if err == errListenerClosed { + close(ln.ch) + return + } + + if errCount > 0 { + time.Sleep(500 * time.Millisecond) + } + errCount++ + + continue + } + + errCount = 0 + + // Any notification is as good as a ping. + select { + case ln.pingCh <- struct{}{}: + default: + } + + switch channel { + case gopgChannel: + // ignore + default: + timer.Reset(chanSendTimeout) + select { + case ln.ch <- Notification{channel, payload}: + if !timer.Stop() { + <-timer.C + } + case <-timer.C: + internal.Logger.Printf( + ctx, + "pg: %s channel is full for %s (notification is dropped)", + ln, + chanSendTimeout, + ) + } + } + } + }() + + go func() { + timer := time.NewTimer(time.Minute) + timer.Stop() + + healthy := true + for { + timer.Reset(pingTimeout) + select { + case <-ln.pingCh: + healthy = true + if !timer.Stop() { + <-timer.C + } + case <-timer.C: + pingErr := ln.ping() + if healthy { + healthy = false + } else { + if pingErr == nil { + pingErr = errPingTimeout + } + ln.mu.Lock() + ln.reconnect(ctx, pingErr) + ln.mu.Unlock() + } + case <-ln.exit: + return + } + } + }() +} + +func (ln *Listener) ping() error { + _, err := ln.db.Exec("NOTIFY ?", pgChan(gopgChannel)) + return err +} + +func appendIfNotExists(ss []string, es ...string) []string { +loop: + for _, e := range es { + for _, s := range ss { + if s == e { + continue loop + } + } + ss = append(ss, e) + } + return ss +} + +func removeIfExists(ss []string, es ...string) []string { + for _, e := range es { + for i, s := range ss { + if s == e { + last := len(ss) - 1 + ss[i] = ss[last] + ss = ss[:last] + break + } + } + } + return ss +} + +type pgChan string + +var _ types.ValueAppender = pgChan("") + +func (ch pgChan) AppendValue(b []byte, quote int) ([]byte, error) { + if quote == 0 { + return append(b, ch...), nil + } + + b = append(b, '"') + for _, c := range []byte(ch) { + if c == '"' { + b = append(b, '"', '"') + } else { + b = append(b, c) + } + } + b = append(b, '"') + + return b, nil +} diff --git a/vendor/github.com/go-pg/pg/messages.go b/vendor/github.com/go-pg/pg/v10/messages.go similarity index 56% rename from vendor/github.com/go-pg/pg/messages.go rename to vendor/github.com/go-pg/pg/v10/messages.go index 9d71e97f6..eb801a027 100644 --- a/vendor/github.com/go-pg/pg/messages.go +++ b/vendor/github.com/go-pg/pg/v10/messages.go @@ -1,19 +1,26 @@ package pg import ( - "crypto/md5" + "bufio" + "context" + "crypto/md5" //nolint "crypto/tls" + "encoding/binary" "encoding/hex" "errors" "fmt" "io" + "strings" - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/internal/pool" - "github.com/go-pg/pg/orm" - "github.com/go-pg/pg/types" + "mellium.im/sasl" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/orm" + "github.com/go-pg/pg/v10/types" ) +// https://www.postgresql.org/docs/current/protocol-message-formats.html const ( commandCompleteMsg = 'C' errorResponseMsg = 'E' @@ -25,6 +32,11 @@ const ( passwordMessageMsg = 'p' terminateMsg = 'X' + saslInitialResponseMsg = 'p' + authenticationSASLContinueMsg = 'R' + saslResponseMsg = 'p' + authenticationSASLFinalMsg = 'R' + authenticationOK = 0 authenticationCleartextPassword = 3 authenticationMD5Password = 5 @@ -63,8 +75,10 @@ const ( var errEmptyQuery = internal.Errorf("pg: query is empty") -func (db *DB) startup(cn *pool.Conn, user, password, database, appName string) error { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { +func (db *baseDB) startup( + c context.Context, cn *pool.Conn, user, password, database, appName string, +) error { + err := cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { writeStartupMsg(wb, user, database, appName) return nil }) @@ -72,54 +86,61 @@ func (db *DB) startup(cn *pool.Conn, user, password, database, appName string) e return err } - return cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { + return cn.WithReader(c, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { for { - c, msgLen, err := rd.ReadMessageType() + typ, msgLen, err := readMessageType(rd) if err != nil { return err } - switch c { + switch typ { case backendKeyDataMsg: - processId, err := rd.ReadInt32() + processID, err := readInt32(rd) if err != nil { return err } - secretKey, err := rd.ReadInt32() + secretKey, err := readInt32(rd) if err != nil { return err } - cn.ProcessId = processId + cn.ProcessID = processID cn.SecretKey = secretKey case parameterStatusMsg: if err := logParameterStatus(rd, msgLen); err != nil { return err } case authenticationOKMsg: - err := db.auth(cn, rd, user, password) + err := db.auth(c, cn, rd, user, password) if err != nil { return err } case readyForQueryMsg: _, err := rd.ReadN(msgLen) return err + case noticeResponseMsg: + // If we encounter a notice message from the server then we want to try to log it as it might be + // important for the client. If something goes wrong with this we want to fail. At the time of writing + // this the client will fail just encountering a notice during startup. So failing if a bad notice is + // sent is probably better than not failing, especially if we can try to log at least some data from the + // notice. + if err := db.logStartupNotice(rd); err != nil { + return err + } case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return err } return e default: - return fmt.Errorf("pg: unknown startup message response: %q", c) + return fmt.Errorf("pg: unknown startup message response: %q", typ) } } }) } -var errSSLNotSupported = errors.New("pg: SSL is not enabled on the server") - -func (db *DB) enableSSL(cn *pool.Conn, tlsConf *tls.Config) error { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { +func (db *baseDB) enableSSL(c context.Context, cn *pool.Conn, tlsConf *tls.Config) error { + err := cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { writeSSLMsg(wb) return nil }) @@ -127,13 +148,13 @@ func (db *DB) enableSSL(cn *pool.Conn, tlsConf *tls.Config) error { return err } - err = cn.WithReader(db.opt.ReadTimeout, func(rd *pool.Reader) error { + err = cn.WithReader(c, db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { c, err := rd.ReadByte() if err != nil { return err } if c != 'S' { - return errSSLNotSupported + return errors.New("pg: SSL is not enabled on the server") } return nil }) @@ -145,8 +166,10 @@ func (db *DB) enableSSL(cn *pool.Conn, tlsConf *tls.Config) error { return nil } -func (db *DB) auth(cn *pool.Conn, rd *pool.Reader, user, password string) error { - num, err := rd.ReadInt32() +func (db *baseDB) auth( + c context.Context, cn *pool.Conn, rd *pool.ReaderContext, user, password string, +) error { + num, err := readInt32(rd) if err != nil { return err } @@ -155,42 +178,112 @@ func (db *DB) auth(cn *pool.Conn, rd *pool.Reader, user, password string) error case authenticationOK: return nil case authenticationCleartextPassword: - return db.authCleartext(cn, rd, password) + return db.authCleartext(c, cn, rd, password) case authenticationMD5Password: - return db.authMD5(cn, rd, user, password) + return db.authMD5(c, cn, rd, user, password) case authenticationSASL: - return db.authSASL(cn, rd, user, password) + return db.authSASL(c, cn, rd, user, password) default: - return fmt.Errorf("pg: unknown authentication message response: %d", num) + return fmt.Errorf("pg: unknown authentication message response: %q", num) } } -func (db *DB) authCleartext(cn *pool.Conn, rd *pool.Reader, password string) error { - err := cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { +// logStartupNotice will handle notice messages during the startup process. It will parse them and log them for the +// client. Notices are not common and only happen if there is something the client should be aware of. So logging should +// not be a problem. +// Notice messages can be seen in startup: https://www.postgresql.org/docs/13/protocol-flow.html +// Information on the notice message format: https://www.postgresql.org/docs/13/protocol-message-formats.html +// Note: This is true for earlier versions of PostgreSQL as well, I've just included the latest versions of the docs. +func (db *baseDB) logStartupNotice( + rd *pool.ReaderContext, +) error { + message := make([]string, 0) + // Notice messages are null byte delimited key-value pairs. Where the keys are one byte. + for { + // Read the key byte. + fieldType, err := rd.ReadByte() + if err != nil { + return err + } + + // If they key byte (the type of field this data is) is 0 then that means we have reached the end of the notice. + // We can break our loop here and throw our message data into the logger. + if fieldType == 0 { + break + } + + // Read until the next null byte to get the data for this field. This does include the null byte at the end of + // fieldValue so we will trim it off down below. + fieldValue, err := readString(rd) + if err != nil { + return err + } + + // Just throw the field type as a string and its value into an array. + // Field types can be seen here: https://www.postgresql.org/docs/13/protocol-error-fields.html + // TODO This is a rare occurrence as is, would it be worth adding something to indicate what the field names + // are? Or is PostgreSQL documentation enough for a user at this point? + message = append(message, fmt.Sprintf("%s: %s", string(fieldType), fieldValue)) + } + + // Tell the client what PostgreSQL told us. Warning because its probably something the client should at the very + // least adjust. + internal.Warn.Printf("notice during startup: %s", strings.Join(message, ", ")) + + return nil +} + +func (db *baseDB) authCleartext( + c context.Context, cn *pool.Conn, rd *pool.ReaderContext, password string, +) error { + err := cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { writePasswordMsg(wb, password) return nil }) if err != nil { return err } + return readAuthOK(rd) +} + +func (db *baseDB) authMD5( + c context.Context, cn *pool.Conn, rd *pool.ReaderContext, user, password string, +) error { + b, err := rd.ReadN(4) + if err != nil { + return err + } + + secret := "md5" + md5s(md5s(password+user)+string(b)) + err = cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + writePasswordMsg(wb, secret) + return nil + }) + if err != nil { + return err + } + + return readAuthOK(rd) +} - c, _, err := rd.ReadMessageType() +func readAuthOK(rd *pool.ReaderContext) error { + c, _, err := readMessageType(rd) if err != nil { return err } switch c { case authenticationOKMsg: - code, err := rd.ReadInt32() + c0, err := readInt32(rd) if err != nil { return err } - if code != 0 { - return fmt.Errorf("pg: unexpected authentication code: %d", code) + if c0 != 0 { + return fmt.Errorf("pg: unexpected authentication code: %q", c0) } return nil case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return err } @@ -200,54 +293,154 @@ func (db *DB) authCleartext(cn *pool.Conn, rd *pool.Reader, password string) err } } -func (db *DB) authMD5(cn *pool.Conn, rd *pool.Reader, user, password string) error { - b, err := rd.ReadN(4) +func (db *baseDB) authSASL( + c context.Context, cn *pool.Conn, rd *pool.ReaderContext, user, password string, +) error { + var saslMech sasl.Mechanism + +loop: + for { + s, err := readString(rd) + if err != nil { + return err + } + + switch s { + case "": + break loop + case sasl.ScramSha256.Name: + saslMech = sasl.ScramSha256 + case sasl.ScramSha256Plus.Name: + // ignore + default: + return fmt.Errorf("got %q, wanted %q", s, sasl.ScramSha256.Name) + } + } + + creds := sasl.Credentials(func() (Username, Password, Identity []byte) { + return []byte(user), []byte(password), nil + }) + client := sasl.NewClient(saslMech, creds) + + _, resp, err := client.Step(nil) if err != nil { return err } - secret := "md5" + md5s(md5s(password+user)+string(b)) - err = cn.WithWriter(db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { - writePasswordMsg(wb, secret) + err = cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + wb.StartMessage(saslInitialResponseMsg) + wb.WriteString(saslMech.Name) + wb.WriteInt32(int32(len(resp))) + _, err := wb.Write(resp) + if err != nil { + return err + } + wb.FinishMessage() return nil }) if err != nil { return err } - c, _, err := rd.ReadMessageType() + typ, n, err := readMessageType(rd) if err != nil { return err } - switch c { - case authenticationOKMsg: - code, err := rd.ReadInt32() + + switch typ { + case authenticationSASLContinueMsg: + c11, err := readInt32(rd) if err != nil { return err } - if code != 0 { - return fmt.Errorf("pg: unexpected authentication code: %d", code) + if c11 != 11 { + return fmt.Errorf("pg: SASL: got %q, wanted %q", typ, 11) } - return nil + + b, err := rd.ReadN(n - 4) + if err != nil { + return err + } + + _, resp, err = client.Step(b) + if err != nil { + return err + } + + err = cn.WithWriter(c, db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + wb.StartMessage(saslResponseMsg) + _, err := wb.Write(resp) + if err != nil { + return err + } + wb.FinishMessage() + return nil + }) + if err != nil { + return err + } + + return readAuthSASLFinal(rd, client) case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return err } return e default: - return fmt.Errorf("pg: unknown password message response: %q", c) + return fmt.Errorf( + "pg: SASL: got %q, wanted %q", typ, authenticationSASLContinueMsg) } } -func (db *DB) authSASL(cn *pool.Conn, rd *pool.Reader, user, password string) error { - return fmt.Errorf("pg: SASL authentication is not supported") +func readAuthSASLFinal(rd *pool.ReaderContext, client *sasl.Negotiator) error { + c, n, err := readMessageType(rd) + if err != nil { + return err + } + + switch c { + case authenticationSASLFinalMsg: + c12, err := readInt32(rd) + if err != nil { + return err + } + if c12 != 12 { + return fmt.Errorf("pg: SASL: got %q, wanted %q", c, 12) + } + + b, err := rd.ReadN(n - 4) + if err != nil { + return err + } + + _, _, err = client.Step(b) + if err != nil { + return err + } + + if client.State() != sasl.ValidServerResponse { + return fmt.Errorf("pg: SASL: state=%q, wanted %q", + client.State(), sasl.ValidServerResponse) + } + case errorResponseMsg: + e, err := readError(rd) + if err != nil { + return err + } + return e + default: + return fmt.Errorf( + "pg: SASL: got %q, wanted %q", c, authenticationSASLFinalMsg) + } + + return readAuthOK(rd) } func md5s(s string) string { - h := md5.New() - h.Write([]byte(s)) - return hex.EncodeToString(h.Sum(nil)) + //nolint + h := md5.Sum([]byte(s)) + return hex.EncodeToString(h[:]) } func writeStartupMsg(buf *pool.WriteBuffer, user, database, appName string) { @@ -282,32 +475,51 @@ func writeFlushMsg(buf *pool.WriteBuffer) { buf.FinishMessage() } -func writeCancelRequestMsg(buf *pool.WriteBuffer, processId, secretKey int32) { +func writeCancelRequestMsg(buf *pool.WriteBuffer, processID, secretKey int32) { buf.StartMessage(0) buf.WriteInt32(80877102) - buf.WriteInt32(processId) + buf.WriteInt32(processID) buf.WriteInt32(secretKey) buf.FinishMessage() } -func writeQueryMsg(buf *pool.WriteBuffer, fmter orm.QueryFormatter, query interface{}, params ...interface{}) error { +func writeQueryMsg( + buf *pool.WriteBuffer, + fmter orm.QueryFormatter, + query interface{}, + params ...interface{}, +) error { buf.StartMessage(queryMsg) - bytes, err := appendQuery(buf.Bytes, fmter, query, params...) + bytes, err := appendQuery(fmter, buf.Bytes, query, params...) if err != nil { - buf.Reset() return err } buf.Bytes = bytes - buf.WriteByte(0x0) + err = buf.WriteByte(0x0) + if err != nil { + return err + } buf.FinishMessage() return nil } -func appendQuery(dst []byte, fmter orm.QueryFormatter, query interface{}, params ...interface{}) ([]byte, error) { +func appendQuery(fmter orm.QueryFormatter, dst []byte, query interface{}, params ...interface{}) ([]byte, error) { switch query := query.(type) { case orm.QueryAppender: - return query.AppendQuery(dst) + if v, ok := fmter.(*orm.Formatter); ok { + fmter = v.WithModel(query) + } + return query.AppendQuery(fmter, dst) case string: + if len(params) > 0 { + model, ok := params[len(params)-1].(orm.TableModel) + if ok { + if v, ok := fmter.(*orm.Formatter); ok { + fmter = v.WithTableModel(model) + params = params[:len(params)-1] + } + } + } return fmter.FormatQuery(dst, query, params...), nil default: return nil, fmt.Errorf("pg: can't append %T", query) @@ -327,18 +539,18 @@ func writeParseDescribeSyncMsg(buf *pool.WriteBuffer, name, q string) { buf.FinishMessage() buf.StartMessage(describeMsg) - buf.WriteByte('S') + buf.WriteByte('S') //nolint buf.WriteString(name) buf.FinishMessage() writeSyncMsg(buf) } -func readParseDescribeSync(rd *pool.Reader) ([][]byte, error) { - var columns [][]byte +func readParseDescribeSync(rd *pool.ReaderContext) ([]types.ColumnInfo, error) { + var columns []types.ColumnInfo var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } @@ -349,7 +561,7 @@ func readParseDescribeSync(rd *pool.Reader) ([][]byte, error) { return nil, err } case rowDescriptionMsg: // Response to the DESCRIBE message. - columns, err = readRowDescription(rd, nil) + columns, err = readRowDescription(rd, pool.NewColumnAlloc()) if err != nil { return nil, err } @@ -373,7 +585,7 @@ func readParseDescribeSync(rd *pool.Reader) ([][]byte, error) { } return columns, err case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -389,7 +601,7 @@ func readParseDescribeSync(rd *pool.Reader) ([][]byte, error) { return nil, err } default: - return nil, fmt.Errorf("pg: readParseDescribeSync: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readParseDescribeSync: unexpected message %q", c) } } } @@ -426,14 +638,14 @@ func writeBindExecuteMsg(buf *pool.WriteBuffer, name string, params ...interface func writeCloseMsg(buf *pool.WriteBuffer, name string) { buf.StartMessage(closeMsg) - buf.WriteByte('S') + buf.WriteByte('S') //nolint buf.WriteString(name) buf.FinishMessage() } -func readCloseCompleteMsg(rd *pool.Reader) error { +func readCloseCompleteMsg(rd *pool.ReaderContext) error { for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return err } @@ -442,7 +654,7 @@ func readCloseCompleteMsg(rd *pool.Reader) error { _, err := rd.ReadN(msgLen) return err case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return err } @@ -456,16 +668,16 @@ func readCloseCompleteMsg(rd *pool.Reader) error { return err } default: - return fmt.Errorf("pg: readCloseCompleteMsg: unexpected message %#x", c) + return fmt.Errorf("pg: readCloseCompleteMsg: unexpected message %q", c) } } } -func readSimpleQuery(rd *pool.Reader) (*result, error) { +func readSimpleQuery(rd *pool.ReaderContext) (*result, error) { var res result var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } @@ -494,13 +706,12 @@ func readSimpleQuery(rd *pool.Reader) (*result, error) { return nil, err } case dataRowMsg: - _, err := rd.ReadN(msgLen) - if err != nil { + if _, err := rd.Discard(msgLen); err != nil { return nil, err } res.returned++ case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -520,16 +731,16 @@ func readSimpleQuery(rd *pool.Reader) (*result, error) { return nil, err } default: - return nil, fmt.Errorf("pg: readSimpleQuery: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readSimpleQuery: unexpected message %q", c) } } } -func readExtQuery(rd *pool.Reader) (*result, error) { +func readExtQuery(rd *pool.ReaderContext) (*result, error) { var res result var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } @@ -564,7 +775,7 @@ func readExtQuery(rd *pool.Reader) (*result, error) { } return &res, nil case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -584,70 +795,97 @@ func readExtQuery(rd *pool.Reader) (*result, error) { return nil, err } default: - return nil, fmt.Errorf("pg: readExtQuery: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readExtQuery: unexpected message %q", c) } } } -func readRowDescription(rd *pool.Reader, columns [][]byte) ([][]byte, error) { - colNum, err := rd.ReadInt16() +func readRowDescription( + rd *pool.ReaderContext, columnAlloc *pool.ColumnAlloc, +) ([]types.ColumnInfo, error) { + numCol, err := readInt16(rd) if err != nil { return nil, err } - columns = setByteSliceLen(columns, int(colNum)) - for i := 0; i < int(colNum); i++ { + for i := 0; i < int(numCol); i++ { b, err := rd.ReadSlice(0) if err != nil { return nil, err } - columns[i] = append(columns[i][:0], b[:len(b)-1]...) - _, err = rd.ReadN(18) - if err != nil { + col := columnAlloc.New(int16(i), b[:len(b)-1]) + + if _, err := rd.ReadN(6); err != nil { return nil, err } - } - return columns, nil -} + dataType, err := readInt32(rd) + if err != nil { + return nil, err + } + col.DataType = dataType -func setByteSliceLen(b [][]byte, n int) [][]byte { - if n <= cap(b) { - return b[:n] + if _, err := rd.ReadN(8); err != nil { + return nil, err + } } - b = b[:cap(b)] - b = append(b, make([][]byte, n-cap(b))...) - return b + + return columnAlloc.Columns(), nil } -func readDataRow(rd *pool.Reader, scanner orm.ColumnScanner, columns [][]byte) error { - colNum, err := rd.ReadInt16() +func readDataRow( + ctx context.Context, + rd *pool.ReaderContext, + columns []types.ColumnInfo, + scanner orm.ColumnScanner, +) error { + numCol, err := readInt16(rd) if err != nil { return err } + if h, ok := scanner.(orm.BeforeScanHook); ok { + if err := h.BeforeScan(ctx); err != nil { + return err + } + } + var firstErr error - for colIdx := int16(0); colIdx < colNum; colIdx++ { - l, err := rd.ReadInt32() + + for colIdx := int16(0); colIdx < numCol; colIdx++ { + n, err := readInt32(rd) if err != nil { return err } - var b []byte - if l != -1 { // NULL - b, err = rd.ReadN(int(l)) - if err != nil { - return err - } + var colRd types.Reader + if int(n) <= rd.Buffered() { + colRd = rd.BytesReader(int(n)) + } else { + rd.SetAvailable(int(n)) + colRd = rd } - column := internal.BytesToString(columns[colIdx]) - err = scanner.ScanColumn(int(colIdx), column, b) - if err != nil && firstErr == nil { + column := columns[colIdx] + if err := scanner.ScanColumn(column, colRd, int(n)); err != nil && firstErr == nil { firstErr = internal.Errorf(err.Error()) } + if rd == colRd { + if rd.Available() > 0 { + if _, err := rd.Discard(rd.Available()); err != nil && firstErr == nil { + firstErr = err + } + } + rd.SetAvailable(-1) + } + } + + if h, ok := scanner.(orm.AfterScanHook); ok { + if err := h.AfterScan(ctx); err != nil { + return err + } } return firstErr @@ -661,18 +899,21 @@ func newModel(mod interface{}) (orm.Model, error) { return m, m.Init() } -func readSimpleQueryData(rd *pool.Reader, mod interface{}) (*result, error) { +func readSimpleQueryData( + ctx context.Context, rd *pool.ReaderContext, mod interface{}, +) (*result, error) { + var columns []types.ColumnInfo var res result var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } switch c { case rowDescriptionMsg: - rd.Columns, err = readRowDescription(rd, rd.Columns[:0]) + columns, err = readRowDescription(rd, rd.ColumnAlloc) if err != nil { return nil, err } @@ -688,12 +929,12 @@ func readSimpleQueryData(rd *pool.Reader, mod interface{}) (*result, error) { } } case dataRowMsg: - m := res.model.NewModel() - if err := readDataRow(rd, m, rd.Columns); err != nil { + scanner := res.model.NextColumnScanner() + if err := readDataRow(ctx, rd, columns, scanner); err != nil { if firstErr == nil { firstErr = err } - } else if err := res.model.AddModel(m); err != nil { + } else if err := res.model.AddColumnScanner(scanner); err != nil { if firstErr == nil { firstErr = err } @@ -718,7 +959,7 @@ func readSimpleQueryData(rd *pool.Reader, mod interface{}) (*result, error) { } return &res, nil case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -738,16 +979,18 @@ func readSimpleQueryData(rd *pool.Reader, mod interface{}) (*result, error) { return nil, err } default: - return nil, fmt.Errorf("pg: readSimpleQueryData: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readSimpleQueryData: unexpected message %q", c) } } } -func readExtQueryData(rd *pool.Reader, mod interface{}, columns [][]byte) (*result, error) { +func readExtQueryData( + ctx context.Context, rd *pool.ReaderContext, mod interface{}, columns []types.ColumnInfo, +) (*result, error) { var res result var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } @@ -770,12 +1013,12 @@ func readExtQueryData(rd *pool.Reader, mod interface{}, columns [][]byte) (*resu } } - m := res.model.NewModel() - if err := readDataRow(rd, m, columns); err != nil { + scanner := res.model.NextColumnScanner() + if err := readDataRow(ctx, rd, columns, scanner); err != nil { if firstErr == nil { firstErr = err } - } else if err := res.model.AddModel(m); err != nil { + } else if err := res.model.AddColumnScanner(scanner); err != nil { if firstErr == nil { firstErr = err } @@ -800,7 +1043,7 @@ func readExtQueryData(rd *pool.Reader, mod interface{}, columns [][]byte) (*resu } return &res, nil case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -816,15 +1059,15 @@ func readExtQueryData(rd *pool.Reader, mod interface{}, columns [][]byte) (*resu return nil, err } default: - return nil, fmt.Errorf("pg: readExtQueryData: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readExtQueryData: unexpected message %q", c) } } } -func readCopyInResponse(rd *pool.Reader) error { +func readCopyInResponse(rd *pool.ReaderContext) error { var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return err } @@ -834,7 +1077,7 @@ func readCopyInResponse(rd *pool.Reader) error { _, err := rd.ReadN(msgLen) return err case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return err } @@ -856,15 +1099,15 @@ func readCopyInResponse(rd *pool.Reader) error { return err } default: - return fmt.Errorf("pg: readCopyInResponse: unexpected message %#x", c) + return fmt.Errorf("pg: readCopyInResponse: unexpected message %q", c) } } } -func readCopyOutResponse(rd *pool.Reader) error { +func readCopyOutResponse(rd *pool.ReaderContext) error { var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return err } @@ -874,7 +1117,7 @@ func readCopyOutResponse(rd *pool.Reader) error { _, err := rd.ReadN(msgLen) return err case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return err } @@ -896,30 +1139,34 @@ func readCopyOutResponse(rd *pool.Reader) error { return err } default: - return fmt.Errorf("pg: readCopyOutResponse: unexpected message %#x", c) + return fmt.Errorf("pg: readCopyOutResponse: unexpected message %q", c) } } } -func readCopyData(rd *pool.Reader, w io.Writer) (*result, error) { +func readCopyData(rd *pool.ReaderContext, w io.Writer) (*result, error) { var res result var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } switch c { case copyDataMsg: - b, err := rd.ReadN(msgLen) - if err != nil { - return nil, err - } + for msgLen > 0 { + b, err := rd.ReadN(msgLen) + if err != nil && err != bufio.ErrBufferFull { + return nil, err + } - _, err = w.Write(b) - if err != nil { - return nil, err + _, err = w.Write(b) + if err != nil { + return nil, err + } + + msgLen -= len(b) } case copyDoneMsg: _, err := rd.ReadN(msgLen) @@ -944,7 +1191,7 @@ func readCopyData(rd *pool.Reader, w io.Writer) (*result, error) { } return &res, nil case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -958,7 +1205,7 @@ func readCopyData(rd *pool.Reader, w io.Writer) (*result, error) { return nil, err } default: - return nil, fmt.Errorf("pg: readCopyData: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readCopyData: unexpected message %q", c) } } } @@ -975,11 +1222,11 @@ func writeCopyDone(buf *pool.WriteBuffer) { buf.FinishMessage() } -func readReadyForQuery(rd *pool.Reader) (*result, error) { +func readReadyForQuery(rd *pool.ReaderContext) (*result, error) { var res result var firstErr error for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return nil, err } @@ -1003,7 +1250,7 @@ func readReadyForQuery(rd *pool.Reader) (*result, error) { } return &res, nil case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return nil, err } @@ -1019,14 +1266,14 @@ func readReadyForQuery(rd *pool.Reader) (*result, error) { return nil, err } default: - return nil, fmt.Errorf("pg: readReadyForQueryOrError: unexpected message %#x", c) + return nil, fmt.Errorf("pg: readReadyForQueryOrError: unexpected message %q", c) } } } -func readNotification(rd *pool.Reader) (channel, payload string, err error) { +func readNotification(rd *pool.ReaderContext) (channel, payload string, err error) { for { - c, msgLen, err := rd.ReadMessageType() + c, msgLen, err := readMessageType(rd) if err != nil { return "", "", err } @@ -1043,7 +1290,7 @@ func readNotification(rd *pool.Reader) (channel, payload string, err error) { return "", "", err } case errorResponseMsg: - e, err := rd.ReadError() + e, err := readError(rd) if err != nil { return "", "", err } @@ -1053,21 +1300,21 @@ func readNotification(rd *pool.Reader) (channel, payload string, err error) { return "", "", err } case notificationResponseMsg: - _, err := rd.ReadInt32() + _, err := readInt32(rd) if err != nil { return "", "", err } - channel, err = rd.ReadString() + channel, err = readString(rd) if err != nil { return "", "", err } - payload, err = rd.ReadString() + payload, err = readString(rd) if err != nil { return "", "", err } return channel, payload, nil default: - return "", "", fmt.Errorf("pg: unexpected message %q", c) + return "", "", fmt.Errorf("pg: readNotification: unexpected message %q", c) } } } @@ -1082,12 +1329,67 @@ func terminateConn(cn *pool.Conn) error { //------------------------------------------------------------------------------ -func logNotice(rd *pool.Reader, msgLen int) error { +func logNotice(rd *pool.ReaderContext, msgLen int) error { _, err := rd.ReadN(msgLen) return err } -func logParameterStatus(rd *pool.Reader, msgLen int) error { +func logParameterStatus(rd *pool.ReaderContext, msgLen int) error { _, err := rd.ReadN(msgLen) return err } + +func readInt16(rd *pool.ReaderContext) (int16, error) { + b, err := rd.ReadN(2) + if err != nil { + return 0, err + } + return int16(binary.BigEndian.Uint16(b)), nil +} + +func readInt32(rd *pool.ReaderContext) (int32, error) { + b, err := rd.ReadN(4) + if err != nil { + return 0, err + } + return int32(binary.BigEndian.Uint32(b)), nil +} + +func readString(rd *pool.ReaderContext) (string, error) { + b, err := rd.ReadSlice(0) + if err != nil { + return "", err + } + return string(b[:len(b)-1]), nil +} + +func readError(rd *pool.ReaderContext) (error, error) { + m := make(map[byte]string) + for { + c, err := rd.ReadByte() + if err != nil { + return nil, err + } + if c == 0 { + break + } + s, err := readString(rd) + if err != nil { + return nil, err + } + m[c] = s + } + return internal.NewPGError(m), nil +} + +func readMessageType(rd *pool.ReaderContext) (byte, int, error) { + c, err := rd.ReadByte() + if err != nil { + return 0, 0, err + } + l, err := readInt32(rd) + if err != nil { + return 0, 0, err + } + return c, int(l) - 4, nil +} diff --git a/vendor/github.com/go-pg/pg/options.go b/vendor/github.com/go-pg/pg/v10/options.go similarity index 58% rename from vendor/github.com/go-pg/pg/options.go rename to vendor/github.com/go-pg/pg/v10/options.go index 11e249737..df05ebcd7 100644 --- a/vendor/github.com/go-pg/pg/options.go +++ b/vendor/github.com/go-pg/pg/v10/options.go @@ -1,19 +1,22 @@ package pg import ( + "context" "crypto/tls" "errors" "fmt" "net" "net/url" + "os" "runtime" + "strconv" "strings" "time" - "github.com/go-pg/pg/internal/pool" + "github.com/go-pg/pg/v10/internal/pool" ) -// Database connection options. +// Options contains database connection options. type Options struct { // Network type, either tcp or unix. // Default is tcp. @@ -23,22 +26,34 @@ type Options struct { // Dialer creates new network connection and has priority over // Network and Addr options. - Dialer func(network, addr string) (net.Conn, error) + Dialer func(ctx context.Context, network, addr string) (net.Conn, error) - // Hook that is called when new connection is established. - OnConnect func(*DB) error + // Hook that is called after new connection is established + // and user is authenticated. + OnConnect func(ctx context.Context, cn *Conn) error User string Password string Database string // ApplicationName is the application name. Used in logs on Pg side. - // Only availaible from pg-9.0. + // Only available from pg-9.0. ApplicationName string // TLS config for secure connections. TLSConfig *tls.Config + // Dial timeout for establishing new connections. + // Default is 5 seconds. + DialTimeout time.Duration + + // Timeout for socket reads. If reached, commands will fail + // with a timeout instead of blocking. + ReadTimeout time.Duration + // Timeout for socket writes. If reached, commands will fail + // with a timeout instead of blocking. + WriteTimeout time.Duration + // Maximum number of retries before giving up. // Default is to not retry failed queries. MaxRetries int @@ -51,17 +66,6 @@ type Options struct { // Default is 4 seconds; -1 disables backoff. MaxRetryBackoff time.Duration - // Dial timeout for establishing new connections. - // Default is 5 seconds. - DialTimeout time.Duration - - // Timeout for socket reads. If reached, commands will fail - // with a timeout instead of blocking. - ReadTimeout time.Duration - // Timeout for socket writes. If reached, commands will fail - // with a timeout instead of blocking. - WriteTimeout time.Duration - // Maximum number of socket connections. // Default is 10 connections per every CPU as reported by runtime.NumCPU. PoolSize int @@ -96,12 +100,35 @@ func (opt *Options) init() { if opt.Addr == "" { switch opt.Network { case "tcp": - opt.Addr = "localhost:5432" + host := env("PGHOST", "localhost") + port := env("PGPORT", "5432") + opt.Addr = fmt.Sprintf("%s:%s", host, port) case "unix": opt.Addr = "/var/run/postgresql/.s.PGSQL.5432" } } + if opt.DialTimeout == 0 { + opt.DialTimeout = 5 * time.Second + } + if opt.Dialer == nil { + opt.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) { + netDialer := &net.Dialer{ + Timeout: opt.DialTimeout, + KeepAlive: 5 * time.Minute, + } + return netDialer.DialContext(ctx, network, addr) + } + } + + if opt.User == "" { + opt.User = env("PGUSER", "postgres") + } + + if opt.Database == "" { + opt.Database = env("PGDATABASE", "postgres") + } + if opt.PoolSize == 0 { opt.PoolSize = 10 * runtime.NumCPU() } @@ -114,10 +141,6 @@ func (opt *Options) init() { } } - if opt.DialTimeout == 0 { - opt.DialTimeout = 5 * time.Second - } - if opt.IdleTimeout == 0 { opt.IdleTimeout = 5 * time.Minute } @@ -139,31 +162,39 @@ func (opt *Options) init() { } } +func env(key, defValue string) string { + envValue := os.Getenv(key) + if envValue != "" { + return envValue + } + return defValue +} + // ParseURL parses an URL into options that can be used to connect to PostgreSQL. func ParseURL(sURL string) (*Options, error) { - parsedUrl, err := url.Parse(sURL) + parsedURL, err := url.Parse(sURL) if err != nil { return nil, err } // scheme - if parsedUrl.Scheme != "postgres" && parsedUrl.Scheme != "postgresql" { - return nil, errors.New("pg: invalid scheme: " + parsedUrl.Scheme) + if parsedURL.Scheme != "postgres" && parsedURL.Scheme != "postgresql" { + return nil, errors.New("pg: invalid scheme: " + parsedURL.Scheme) } // host and port options := &Options{ - Addr: parsedUrl.Host, + Addr: parsedURL.Host, } if !strings.Contains(options.Addr, ":") { - options.Addr = options.Addr + ":5432" + options.Addr += ":5432" } // username and password - if parsedUrl.User != nil { - options.User = parsedUrl.User.Username() + if parsedURL.User != nil { + options.User = parsedURL.User.Username() - if password, ok := parsedUrl.User.Password(); ok { + if password, ok := parsedURL.User.Password(); ok { options.Password = password } } @@ -173,29 +204,31 @@ func ParseURL(sURL string) (*Options, error) { } // database - if len(strings.Trim(parsedUrl.Path, "/")) > 0 { - options.Database = parsedUrl.Path[1:] + if len(strings.Trim(parsedURL.Path, "/")) > 0 { + options.Database = parsedURL.Path[1:] } else { return nil, errors.New("pg: database name not provided") } // ssl mode - query, err := url.ParseQuery(parsedUrl.RawQuery) + query, err := url.ParseQuery(parsedURL.RawQuery) if err != nil { return nil, err } if sslMode, ok := query["sslmode"]; ok && len(sslMode) > 0 { switch sslMode[0] { + case "verify-ca", "verify-full": + options.TLSConfig = &tls.Config{} case "allow", "prefer", "require": - options.TLSConfig = &tls.Config{InsecureSkipVerify: true} + options.TLSConfig = &tls.Config{InsecureSkipVerify: true} //nolint case "disable": options.TLSConfig = nil default: - return nil, errors.New(fmt.Sprintf("pg: sslmode '%v' is not supported", sslMode[0])) + return nil, fmt.Errorf("pg: sslmode '%v' is not supported", sslMode[0]) } } else { - options.TLSConfig = &tls.Config{InsecureSkipVerify: true} + options.TLSConfig = &tls.Config{InsecureSkipVerify: true} //nolint } delete(query, "sslmode") @@ -206,37 +239,86 @@ func ParseURL(sURL string) (*Options, error) { delete(query, "application_name") + if connTimeout, ok := query["connect_timeout"]; ok && len(connTimeout) > 0 { + ct, err := strconv.Atoi(connTimeout[0]) + if err != nil { + return nil, fmt.Errorf("pg: cannot parse connect_timeout option as int") + } + options.DialTimeout = time.Second * time.Duration(ct) + } + + delete(query, "connect_timeout") + if len(query) > 0 { - return nil, errors.New("pg: options other than 'sslmode' and 'application_name' are not supported") + return nil, errors.New("pg: options other than 'sslmode', 'application_name' and 'connect_timeout' are not supported") } return options, nil } -func (opt *Options) getDialer() func() (net.Conn, error) { - if opt.Dialer != nil { - return func() (net.Conn, error) { - return opt.Dialer(opt.Network, opt.Addr) +func (opts *Options) ToURL() string { + dsn := "postgres://" + + if len(opts.User) > 0 { + dsn += opts.User + + if len(opts.Password) > 0 { + dsn += ":" + opts.Password } + + dsn += "@" } - return func() (net.Conn, error) { - netDialer := &net.Dialer{ - Timeout: opt.DialTimeout, - KeepAlive: 5 * time.Minute, - } - return netDialer.Dial(opt.Network, opt.Addr) + + if len(opts.Addr) > 0 { + dsn += opts.Addr + } else { + dsn += "localhost:5432" + } + + dsn += "/" + opts.Database + + values := url.Values{} + + if opts.DialTimeout > 0 { + values.Add("connect_timeout", strconv.Itoa(int(opts.DialTimeout)/int(time.Second))) + } + + if len(opts.ApplicationName) > 0 { + values.Add("application_name", opts.ApplicationName) + } + + if opts.TLSConfig == nil { + values.Add("sslmode", "disable") + } else if opts.TLSConfig.InsecureSkipVerify { + values.Add("sslmode", "allow") + } else if !opts.TLSConfig.InsecureSkipVerify { + values.Add("sslmode", "verify-ca") + } + + encoded := values.Encode() + if len(encoded) > 0 { + dsn += "?" + encoded + } + + return dsn +} + +func (opt *Options) getDialer() func(context.Context) (net.Conn, error) { + return func(ctx context.Context) (net.Conn, error) { + return opt.Dialer(ctx, opt.Network, opt.Addr) } } func newConnPool(opt *Options) *pool.ConnPool { return pool.NewConnPool(&pool.Options{ - Dialer: opt.getDialer(), + Dialer: opt.getDialer(), + OnClose: terminateConn, + PoolSize: opt.PoolSize, + MinIdleConns: opt.MinIdleConns, + MaxConnAge: opt.MaxConnAge, PoolTimeout: opt.PoolTimeout, IdleTimeout: opt.IdleTimeout, IdleCheckFrequency: opt.IdleCheckFrequency, - OnClose: func(cn *pool.Conn) error { - return terminateConn(cn) - }, }) } diff --git a/vendor/github.com/go-pg/pg/v10/orm/composite.go b/vendor/github.com/go-pg/pg/v10/orm/composite.go new file mode 100644 index 000000000..d2e48a8b3 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/composite.go @@ -0,0 +1,100 @@ +package orm + +import ( + "fmt" + "reflect" + + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/types" +) + +func compositeScanner(typ reflect.Type) types.ScannerFunc { + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + + var table *Table + return func(v reflect.Value, rd types.Reader, n int) error { + if n == -1 { + v.Set(reflect.Zero(v.Type())) + return nil + } + + if table == nil { + table = GetTable(typ) + } + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + + p := newCompositeParser(rd) + var elemReader *pool.BytesReader + + var firstErr error + for i := 0; ; i++ { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfComposite { + break + } + return err + } + + if i >= len(table.Fields) { + if firstErr == nil { + firstErr = fmt.Errorf( + "pg: %s has %d fields, but composite requires at least %d values", + table, len(table.Fields), i) + } + continue + } + + if elemReader == nil { + elemReader = pool.NewBytesReader(elem) + } else { + elemReader.Reset(elem) + } + + field := table.Fields[i] + if elem == nil { + err = field.ScanValue(v, elemReader, -1) + } else { + err = field.ScanValue(v, elemReader, len(elem)) + } + if err != nil && firstErr == nil { + firstErr = err + } + } + + return firstErr + } +} + +func compositeAppender(typ reflect.Type) types.AppenderFunc { + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + + var table *Table + return func(b []byte, v reflect.Value, quote int) []byte { + if table == nil { + table = GetTable(typ) + } + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + b = append(b, "ROW("...) + for i, f := range table.Fields { + if i > 0 { + b = append(b, ',') + } + b = f.AppendValue(b, v, quote) + } + b = append(b, ')') + return b + } +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/composite_create.go b/vendor/github.com/go-pg/pg/v10/orm/composite_create.go new file mode 100644 index 000000000..fd60a94e4 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/composite_create.go @@ -0,0 +1,89 @@ +package orm + +import ( + "strconv" +) + +type CreateCompositeOptions struct { + Varchar int // replaces PostgreSQL data type `text` with `varchar(n)` +} + +type CreateCompositeQuery struct { + q *Query + opt *CreateCompositeOptions +} + +var ( + _ QueryAppender = (*CreateCompositeQuery)(nil) + _ QueryCommand = (*CreateCompositeQuery)(nil) +) + +func NewCreateCompositeQuery(q *Query, opt *CreateCompositeOptions) *CreateCompositeQuery { + return &CreateCompositeQuery{ + q: q, + opt: opt, + } +} + +func (q *CreateCompositeQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *CreateCompositeQuery) Operation() QueryOp { + return CreateCompositeOp +} + +func (q *CreateCompositeQuery) Clone() QueryCommand { + return &CreateCompositeQuery{ + q: q.q.Clone(), + opt: q.opt, + } +} + +func (q *CreateCompositeQuery) Query() *Query { + return q.q +} + +func (q *CreateCompositeQuery) AppendTemplate(b []byte) ([]byte, error) { + return q.AppendQuery(dummyFormatter{}, b) +} + +func (q *CreateCompositeQuery) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + if q.q.tableModel == nil { + return nil, errModelNil + } + + table := q.q.tableModel.Table() + + b = append(b, "CREATE TYPE "...) + b = append(b, table.Alias...) + b = append(b, " AS ("...) + + for i, field := range table.Fields { + if i > 0 { + b = append(b, ", "...) + } + + b = append(b, field.Column...) + b = append(b, " "...) + if field.UserSQLType == "" && q.opt != nil && q.opt.Varchar > 0 && + field.SQLType == "text" { + b = append(b, "varchar("...) + b = strconv.AppendInt(b, int64(q.opt.Varchar), 10) + b = append(b, ")"...) + } else { + b = append(b, field.SQLType...) + } + } + + b = append(b, ")"...) + + return b, q.q.stickyErr +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/composite_drop.go b/vendor/github.com/go-pg/pg/v10/orm/composite_drop.go new file mode 100644 index 000000000..2a169b07a --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/composite_drop.go @@ -0,0 +1,70 @@ +package orm + +type DropCompositeOptions struct { + IfExists bool + Cascade bool +} + +type DropCompositeQuery struct { + q *Query + opt *DropCompositeOptions +} + +var ( + _ QueryAppender = (*DropCompositeQuery)(nil) + _ QueryCommand = (*DropCompositeQuery)(nil) +) + +func NewDropCompositeQuery(q *Query, opt *DropCompositeOptions) *DropCompositeQuery { + return &DropCompositeQuery{ + q: q, + opt: opt, + } +} + +func (q *DropCompositeQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *DropCompositeQuery) Operation() QueryOp { + return DropCompositeOp +} + +func (q *DropCompositeQuery) Clone() QueryCommand { + return &DropCompositeQuery{ + q: q.q.Clone(), + opt: q.opt, + } +} + +func (q *DropCompositeQuery) Query() *Query { + return q.q +} + +func (q *DropCompositeQuery) AppendTemplate(b []byte) ([]byte, error) { + return q.AppendQuery(dummyFormatter{}, b) +} + +func (q *DropCompositeQuery) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + if q.q.tableModel == nil { + return nil, errModelNil + } + + b = append(b, "DROP TYPE "...) + if q.opt != nil && q.opt.IfExists { + b = append(b, "IF EXISTS "...) + } + b = append(b, q.q.tableModel.Table().Alias...) + if q.opt != nil && q.opt.Cascade { + b = append(b, " CASCADE"...) + } + + return b, q.q.stickyErr +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/composite_parser.go b/vendor/github.com/go-pg/pg/v10/orm/composite_parser.go new file mode 100644 index 000000000..29e500444 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/composite_parser.go @@ -0,0 +1,140 @@ +package orm + +import ( + "bufio" + "errors" + "fmt" + "io" + + "github.com/go-pg/pg/v10/internal/parser" + "github.com/go-pg/pg/v10/types" +) + +var errEndOfComposite = errors.New("pg: end of composite") + +type compositeParser struct { + p parser.StreamingParser + + stickyErr error +} + +func newCompositeParserErr(err error) *compositeParser { + return &compositeParser{ + stickyErr: err, + } +} + +func newCompositeParser(rd types.Reader) *compositeParser { + p := parser.NewStreamingParser(rd) + err := p.SkipByte('(') + if err != nil { + return newCompositeParserErr(err) + } + return &compositeParser{ + p: p, + } +} + +func (p *compositeParser) NextElem() ([]byte, error) { + if p.stickyErr != nil { + return nil, p.stickyErr + } + + c, err := p.p.ReadByte() + if err != nil { + if err == io.EOF { + return nil, errEndOfComposite + } + return nil, err + } + + switch c { + case '"': + return p.readQuoted() + case ',': + return nil, nil + case ')': + return nil, errEndOfComposite + default: + _ = p.p.UnreadByte() + } + + var b []byte + for { + tmp, err := p.p.ReadSlice(',') + if err == nil { + if b == nil { + b = tmp + } else { + b = append(b, tmp...) + } + b = b[:len(b)-1] + break + } + b = append(b, tmp...) + if err == bufio.ErrBufferFull { + continue + } + if err == io.EOF { + if b[len(b)-1] == ')' { + b = b[:len(b)-1] + break + } + } + return nil, err + } + + if len(b) == 0 { // NULL + return nil, nil + } + return b, nil +} + +func (p *compositeParser) readQuoted() ([]byte, error) { + var b []byte + + c, err := p.p.ReadByte() + if err != nil { + return nil, err + } + + for { + next, err := p.p.ReadByte() + if err != nil { + return nil, err + } + + if c == '\\' || c == '\'' { + if next == c { + b = append(b, c) + c, err = p.p.ReadByte() + if err != nil { + return nil, err + } + } else { + b = append(b, c) + c = next + } + continue + } + + if c == '"' { + switch next { + case '"': + b = append(b, '"') + c, err = p.p.ReadByte() + if err != nil { + return nil, err + } + case ',', ')': + return b, nil + default: + return nil, fmt.Errorf("pg: got %q, wanted ',' or ')'", c) + } + continue + } + + b = append(b, c) + c = next + } +} diff --git a/vendor/github.com/go-pg/pg/orm/count_estimate.go b/vendor/github.com/go-pg/pg/v10/orm/count_estimate.go similarity index 83% rename from vendor/github.com/go-pg/pg/orm/count_estimate.go rename to vendor/github.com/go-pg/pg/v10/orm/count_estimate.go index c8fde32e2..bfa664a72 100644 --- a/vendor/github.com/go-pg/pg/orm/count_estimate.go +++ b/vendor/github.com/go-pg/pg/v10/orm/count_estimate.go @@ -3,13 +3,14 @@ package orm import ( "fmt" - "github.com/go-pg/pg/internal" + "github.com/go-pg/pg/v10/internal" ) // Placeholder that is replaced with count(*). const placeholder = `'_go_pg_placeholder'` // https://wiki.postgresql.org/wiki/Count_estimate +//nolint var pgCountEstimateFunc = fmt.Sprintf(` CREATE OR REPLACE FUNCTION _go_pg_count_estimate_v2(query text, threshold int) RETURNS int AS $$ @@ -51,14 +52,15 @@ func (q *Query) CountEstimate(threshold int) (int, error) { return 0, q.stickyErr } - query, err := q.countSelectQuery(placeholder).AppendQuery(nil) + query, err := q.countSelectQuery(placeholder).AppendQuery(q.db.Formatter(), nil) if err != nil { return 0, err } for i := 0; i < 3; i++ { var count int - _, err = q.db.QueryOne( + _, err = q.db.QueryOneContext( + q.ctx, Scan(&count), "SELECT _go_pg_count_estimate_v2(?, ?)", string(query), threshold, @@ -68,7 +70,10 @@ func (q *Query) CountEstimate(threshold int) (int, error) { // undefined_function err = q.createCountEstimateFunc() if err != nil { - return 0, err + pgerr, ok := err.(internal.PGError) + if !ok || !pgerr.IntegrityViolation() { + return 0, err + } } continue } @@ -80,6 +85,6 @@ func (q *Query) CountEstimate(threshold int) (int, error) { } func (q *Query) createCountEstimateFunc() error { - _, err := q.db.Exec(pgCountEstimateFunc) + _, err := q.db.ExecContext(q.ctx, pgCountEstimateFunc) return err } diff --git a/vendor/github.com/go-pg/pg/v10/orm/delete.go b/vendor/github.com/go-pg/pg/v10/orm/delete.go new file mode 100644 index 000000000..c54cd10f8 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/delete.go @@ -0,0 +1,158 @@ +package orm + +import ( + "reflect" + + "github.com/go-pg/pg/v10/types" +) + +type DeleteQuery struct { + q *Query + placeholder bool +} + +var ( + _ QueryAppender = (*DeleteQuery)(nil) + _ QueryCommand = (*DeleteQuery)(nil) +) + +func NewDeleteQuery(q *Query) *DeleteQuery { + return &DeleteQuery{ + q: q, + } +} + +func (q *DeleteQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *DeleteQuery) Operation() QueryOp { + return DeleteOp +} + +func (q *DeleteQuery) Clone() QueryCommand { + return &DeleteQuery{ + q: q.q.Clone(), + placeholder: q.placeholder, + } +} + +func (q *DeleteQuery) Query() *Query { + return q.q +} + +func (q *DeleteQuery) AppendTemplate(b []byte) ([]byte, error) { + cp := q.Clone().(*DeleteQuery) + cp.placeholder = true + return cp.AppendQuery(dummyFormatter{}, b) +} + +func (q *DeleteQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + + if len(q.q.with) > 0 { + b, err = q.q.appendWith(fmter, b) + if err != nil { + return nil, err + } + } + + b = append(b, "DELETE FROM "...) + b, err = q.q.appendFirstTableWithAlias(fmter, b) + if err != nil { + return nil, err + } + + if q.q.hasMultiTables() { + b = append(b, " USING "...) + b, err = q.q.appendOtherTables(fmter, b) + if err != nil { + return nil, err + } + } + + b = append(b, " WHERE "...) + value := q.q.tableModel.Value() + + if q.q.isSliceModelWithData() { + if len(q.q.where) > 0 { + b, err = q.q.appendWhere(fmter, b) + if err != nil { + return nil, err + } + } else { + table := q.q.tableModel.Table() + err = table.checkPKs() + if err != nil { + return nil, err + } + + b = appendColumnAndSliceValue(fmter, b, value, table.Alias, table.PKs) + } + } else { + b, err = q.q.mustAppendWhere(fmter, b) + if err != nil { + return nil, err + } + } + + if len(q.q.returning) > 0 { + b, err = q.q.appendReturning(fmter, b) + if err != nil { + return nil, err + } + } + + return b, q.q.stickyErr +} + +func appendColumnAndSliceValue( + fmter QueryFormatter, b []byte, slice reflect.Value, alias types.Safe, fields []*Field, +) []byte { + if len(fields) > 1 { + b = append(b, '(') + } + b = appendColumns(b, alias, fields) + if len(fields) > 1 { + b = append(b, ')') + } + + b = append(b, " IN ("...) + + isPlaceholder := isTemplateFormatter(fmter) + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + if i > 0 { + b = append(b, ", "...) + } + + el := indirect(slice.Index(i)) + + if len(fields) > 1 { + b = append(b, '(') + } + for i, f := range fields { + if i > 0 { + b = append(b, ", "...) + } + if isPlaceholder { + b = append(b, '?') + } else { + b = f.AppendValue(b, el, 1) + } + } + if len(fields) > 1 { + b = append(b, ')') + } + } + + b = append(b, ')') + + return b +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/field.go b/vendor/github.com/go-pg/pg/v10/orm/field.go new file mode 100644 index 000000000..9502c2a7c --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/field.go @@ -0,0 +1,147 @@ +package orm + +import ( + "fmt" + "reflect" + + "github.com/go-pg/zerochecker" + + "github.com/go-pg/pg/v10/types" +) + +const ( + PrimaryKeyFlag = uint8(1) << iota + ForeignKeyFlag + NotNullFlag + UseZeroFlag + UniqueFlag + ArrayFlag +) + +type Field struct { + Field reflect.StructField + Type reflect.Type + Index []int + + GoName string // struct field name, e.g. Id + SQLName string // SQL name, .e.g. id + Column types.Safe // escaped SQL name, e.g. "id" + SQLType string + UserSQLType string + Default types.Safe + OnDelete string + OnUpdate string + + flags uint8 + + append types.AppenderFunc + scan types.ScannerFunc + + isZero zerochecker.Func +} + +func indexEqual(ind1, ind2 []int) bool { + if len(ind1) != len(ind2) { + return false + } + for i, ind := range ind1 { + if ind != ind2[i] { + return false + } + } + return true +} + +func (f *Field) Clone() *Field { + cp := *f + cp.Index = cp.Index[:len(f.Index):len(f.Index)] + return &cp +} + +func (f *Field) setFlag(flag uint8) { + f.flags |= flag +} + +func (f *Field) hasFlag(flag uint8) bool { + return f.flags&flag != 0 +} + +func (f *Field) Value(strct reflect.Value) reflect.Value { + return fieldByIndexAlloc(strct, f.Index) +} + +func (f *Field) HasZeroValue(strct reflect.Value) bool { + return f.hasZeroValue(strct, f.Index) +} + +func (f *Field) hasZeroValue(v reflect.Value, index []int) bool { + for _, idx := range index { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return true + } + v = v.Elem() + } + v = v.Field(idx) + } + return f.isZero(v) +} + +func (f *Field) NullZero() bool { + return !f.hasFlag(UseZeroFlag) +} + +func (f *Field) AppendValue(b []byte, strct reflect.Value, quote int) []byte { + fv, ok := fieldByIndex(strct, f.Index) + if !ok { + return types.AppendNull(b, quote) + } + + if f.NullZero() && f.isZero(fv) { + return types.AppendNull(b, quote) + } + if f.append == nil { + panic(fmt.Errorf("pg: AppendValue(unsupported %s)", fv.Type())) + } + return f.append(b, fv, quote) +} + +func (f *Field) ScanValue(strct reflect.Value, rd types.Reader, n int) error { + if f.scan == nil { + return fmt.Errorf("pg: ScanValue(unsupported %s)", f.Type) + } + + var fv reflect.Value + if n == -1 { + var ok bool + fv, ok = fieldByIndex(strct, f.Index) + if !ok { + return nil + } + } else { + fv = fieldByIndexAlloc(strct, f.Index) + } + + return f.scan(fv, rd, n) +} + +type Method struct { + Index int + + flags int8 + + appender func([]byte, reflect.Value, int) []byte +} + +func (m *Method) Has(flag int8) bool { + return m.flags&flag != 0 +} + +func (m *Method) Value(strct reflect.Value) reflect.Value { + return strct.Method(m.Index).Call(nil)[0] +} + +func (m *Method) AppendValue(dst []byte, strct reflect.Value, quote int) []byte { + mv := m.Value(strct) + return m.appender(dst, mv, quote) +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/format.go b/vendor/github.com/go-pg/pg/v10/orm/format.go new file mode 100644 index 000000000..9945f6e1d --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/format.go @@ -0,0 +1,333 @@ +package orm + +import ( + "bytes" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/parser" + "github.com/go-pg/pg/v10/types" +) + +var defaultFmter = NewFormatter() + +type queryWithSepAppender interface { + QueryAppender + AppendSep([]byte) []byte +} + +//------------------------------------------------------------------------------ + +type SafeQueryAppender struct { + query string + params []interface{} +} + +var ( + _ QueryAppender = (*SafeQueryAppender)(nil) + _ types.ValueAppender = (*SafeQueryAppender)(nil) +) + +//nolint +func SafeQuery(query string, params ...interface{}) *SafeQueryAppender { + return &SafeQueryAppender{query, params} +} + +func (q *SafeQueryAppender) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + return fmter.FormatQuery(b, q.query, q.params...), nil +} + +func (q *SafeQueryAppender) AppendValue(b []byte, quote int) ([]byte, error) { + return q.AppendQuery(defaultFmter, b) +} + +func (q *SafeQueryAppender) Value() types.Safe { + b, err := q.AppendValue(nil, 1) + if err != nil { + return types.Safe(err.Error()) + } + return types.Safe(internal.BytesToString(b)) +} + +//------------------------------------------------------------------------------ + +type condGroupAppender struct { + sep string + cond []queryWithSepAppender +} + +var ( + _ QueryAppender = (*condAppender)(nil) + _ queryWithSepAppender = (*condAppender)(nil) +) + +func (q *condGroupAppender) AppendSep(b []byte) []byte { + return append(b, q.sep...) +} + +func (q *condGroupAppender) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + b = append(b, '(') + for i, app := range q.cond { + if i > 0 { + b = app.AppendSep(b) + } + b, err = app.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + b = append(b, ')') + return b, nil +} + +//------------------------------------------------------------------------------ + +type condAppender struct { + sep string + cond string + params []interface{} +} + +var ( + _ QueryAppender = (*condAppender)(nil) + _ queryWithSepAppender = (*condAppender)(nil) +) + +func (q *condAppender) AppendSep(b []byte) []byte { + return append(b, q.sep...) +} + +func (q *condAppender) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + b = append(b, '(') + b = fmter.FormatQuery(b, q.cond, q.params...) + b = append(b, ')') + return b, nil +} + +//------------------------------------------------------------------------------ + +type fieldAppender struct { + field string +} + +var _ QueryAppender = (*fieldAppender)(nil) + +func (a fieldAppender) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + return types.AppendIdent(b, a.field, 1), nil +} + +//------------------------------------------------------------------------------ + +type dummyFormatter struct{} + +func (f dummyFormatter) FormatQuery(b []byte, query string, params ...interface{}) []byte { + return append(b, query...) +} + +func isTemplateFormatter(fmter QueryFormatter) bool { + _, ok := fmter.(dummyFormatter) + return ok +} + +//------------------------------------------------------------------------------ + +type QueryFormatter interface { + FormatQuery(b []byte, query string, params ...interface{}) []byte +} + +type Formatter struct { + namedParams map[string]interface{} + model TableModel +} + +var _ QueryFormatter = (*Formatter)(nil) + +func NewFormatter() *Formatter { + return new(Formatter) +} + +func (f *Formatter) String() string { + if len(f.namedParams) == 0 { + return "" + } + + keys := make([]string, len(f.namedParams)) + index := 0 + for k := range f.namedParams { + keys[index] = k + index++ + } + + sort.Strings(keys) + + ss := make([]string, len(keys)) + for i, k := range keys { + ss[i] = fmt.Sprintf("%s=%v", k, f.namedParams[k]) + } + return " " + strings.Join(ss, " ") +} + +func (f *Formatter) clone() *Formatter { + cp := NewFormatter() + + cp.model = f.model + if len(f.namedParams) > 0 { + cp.namedParams = make(map[string]interface{}, len(f.namedParams)) + } + for param, value := range f.namedParams { + cp.setParam(param, value) + } + + return cp +} + +func (f *Formatter) WithTableModel(model TableModel) *Formatter { + cp := f.clone() + cp.model = model + return cp +} + +func (f *Formatter) WithModel(model interface{}) *Formatter { + switch model := model.(type) { + case TableModel: + return f.WithTableModel(model) + case *Query: + return f.WithTableModel(model.tableModel) + case QueryCommand: + return f.WithTableModel(model.Query().tableModel) + default: + panic(fmt.Errorf("pg: unsupported model %T", model)) + } +} + +func (f *Formatter) setParam(param string, value interface{}) { + if f.namedParams == nil { + f.namedParams = make(map[string]interface{}) + } + f.namedParams[param] = value +} + +func (f *Formatter) WithParam(param string, value interface{}) *Formatter { + cp := f.clone() + cp.setParam(param, value) + return cp +} + +func (f *Formatter) Param(param string) interface{} { + return f.namedParams[param] +} + +func (f *Formatter) hasParams() bool { + return len(f.namedParams) > 0 || f.model != nil +} + +func (f *Formatter) FormatQueryBytes(dst, query []byte, params ...interface{}) []byte { + if (params == nil && !f.hasParams()) || bytes.IndexByte(query, '?') == -1 { + return append(dst, query...) + } + return f.append(dst, parser.New(query), params) +} + +func (f *Formatter) FormatQuery(dst []byte, query string, params ...interface{}) []byte { + if (params == nil && !f.hasParams()) || strings.IndexByte(query, '?') == -1 { + return append(dst, query...) + } + return f.append(dst, parser.NewString(query), params) +} + +func (f *Formatter) append(dst []byte, p *parser.Parser, params []interface{}) []byte { + var paramsIndex int + var namedParamsOnce bool + var tableParams *tableParams + + for p.Valid() { + b, ok := p.ReadSep('?') + if !ok { + dst = append(dst, b...) + continue + } + if len(b) > 0 && b[len(b)-1] == '\\' { + dst = append(dst, b[:len(b)-1]...) + dst = append(dst, '?') + continue + } + dst = append(dst, b...) + + id, numeric := p.ReadIdentifier() + if id != "" { + if numeric { + idx, err := strconv.Atoi(id) + if err != nil { + goto restore_param + } + + if idx >= len(params) { + goto restore_param + } + + dst = f.appendParam(dst, params[idx]) + continue + } + + if f.namedParams != nil { + param, paramOK := f.namedParams[id] + if paramOK { + dst = f.appendParam(dst, param) + continue + } + } + + if !namedParamsOnce && len(params) > 0 { + namedParamsOnce = true + tableParams, _ = newTableParams(params[len(params)-1]) + } + + if tableParams != nil { + dst, ok = tableParams.AppendParam(f, dst, id) + if ok { + continue + } + } + + if f.model != nil { + dst, ok = f.model.AppendParam(f, dst, id) + if ok { + continue + } + } + + restore_param: + dst = append(dst, '?') + dst = append(dst, id...) + continue + } + + if paramsIndex >= len(params) { + dst = append(dst, '?') + continue + } + + param := params[paramsIndex] + paramsIndex++ + + dst = f.appendParam(dst, param) + } + + return dst +} + +func (f *Formatter) appendParam(b []byte, param interface{}) []byte { + switch param := param.(type) { + case QueryAppender: + bb, err := param.AppendQuery(f, b) + if err != nil { + return types.AppendError(b, err) + } + return bb + default: + return types.Append(b, param, 1) + } +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/hook.go b/vendor/github.com/go-pg/pg/v10/orm/hook.go new file mode 100644 index 000000000..78bd10310 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/hook.go @@ -0,0 +1,248 @@ +package orm + +import ( + "context" + "reflect" +) + +type hookStubs struct{} + +var ( + _ AfterScanHook = (*hookStubs)(nil) + _ AfterSelectHook = (*hookStubs)(nil) + _ BeforeInsertHook = (*hookStubs)(nil) + _ AfterInsertHook = (*hookStubs)(nil) + _ BeforeUpdateHook = (*hookStubs)(nil) + _ AfterUpdateHook = (*hookStubs)(nil) + _ BeforeDeleteHook = (*hookStubs)(nil) + _ AfterDeleteHook = (*hookStubs)(nil) +) + +func (hookStubs) AfterScan(ctx context.Context) error { + return nil +} + +func (hookStubs) AfterSelect(ctx context.Context) error { + return nil +} + +func (hookStubs) BeforeInsert(ctx context.Context) (context.Context, error) { + return ctx, nil +} + +func (hookStubs) AfterInsert(ctx context.Context) error { + return nil +} + +func (hookStubs) BeforeUpdate(ctx context.Context) (context.Context, error) { + return ctx, nil +} + +func (hookStubs) AfterUpdate(ctx context.Context) error { + return nil +} + +func (hookStubs) BeforeDelete(ctx context.Context) (context.Context, error) { + return ctx, nil +} + +func (hookStubs) AfterDelete(ctx context.Context) error { + return nil +} + +func callHookSlice( + ctx context.Context, + slice reflect.Value, + ptr bool, + hook func(context.Context, reflect.Value) (context.Context, error), +) (context.Context, error) { + var firstErr error + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + v := slice.Index(i) + if !ptr { + v = v.Addr() + } + + var err error + ctx, err = hook(ctx, v) + if err != nil && firstErr == nil { + firstErr = err + } + } + return ctx, firstErr +} + +func callHookSlice2( + ctx context.Context, + slice reflect.Value, + ptr bool, + hook func(context.Context, reflect.Value) error, +) error { + var firstErr error + if slice.IsValid() { + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + v := slice.Index(i) + if !ptr { + v = v.Addr() + } + + err := hook(ctx, v) + if err != nil && firstErr == nil { + firstErr = err + } + } + } + return firstErr +} + +//------------------------------------------------------------------------------ + +type BeforeScanHook interface { + BeforeScan(context.Context) error +} + +var beforeScanHookType = reflect.TypeOf((*BeforeScanHook)(nil)).Elem() + +func callBeforeScanHook(ctx context.Context, v reflect.Value) error { + return v.Interface().(BeforeScanHook).BeforeScan(ctx) +} + +//------------------------------------------------------------------------------ + +type AfterScanHook interface { + AfterScan(context.Context) error +} + +var afterScanHookType = reflect.TypeOf((*AfterScanHook)(nil)).Elem() + +func callAfterScanHook(ctx context.Context, v reflect.Value) error { + return v.Interface().(AfterScanHook).AfterScan(ctx) +} + +//------------------------------------------------------------------------------ + +type AfterSelectHook interface { + AfterSelect(context.Context) error +} + +var afterSelectHookType = reflect.TypeOf((*AfterSelectHook)(nil)).Elem() + +func callAfterSelectHook(ctx context.Context, v reflect.Value) error { + return v.Interface().(AfterSelectHook).AfterSelect(ctx) +} + +func callAfterSelectHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) error { + return callHookSlice2(ctx, slice, ptr, callAfterSelectHook) +} + +//------------------------------------------------------------------------------ + +type BeforeInsertHook interface { + BeforeInsert(context.Context) (context.Context, error) +} + +var beforeInsertHookType = reflect.TypeOf((*BeforeInsertHook)(nil)).Elem() + +func callBeforeInsertHook(ctx context.Context, v reflect.Value) (context.Context, error) { + return v.Interface().(BeforeInsertHook).BeforeInsert(ctx) +} + +func callBeforeInsertHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) (context.Context, error) { + return callHookSlice(ctx, slice, ptr, callBeforeInsertHook) +} + +//------------------------------------------------------------------------------ + +type AfterInsertHook interface { + AfterInsert(context.Context) error +} + +var afterInsertHookType = reflect.TypeOf((*AfterInsertHook)(nil)).Elem() + +func callAfterInsertHook(ctx context.Context, v reflect.Value) error { + return v.Interface().(AfterInsertHook).AfterInsert(ctx) +} + +func callAfterInsertHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) error { + return callHookSlice2(ctx, slice, ptr, callAfterInsertHook) +} + +//------------------------------------------------------------------------------ + +type BeforeUpdateHook interface { + BeforeUpdate(context.Context) (context.Context, error) +} + +var beforeUpdateHookType = reflect.TypeOf((*BeforeUpdateHook)(nil)).Elem() + +func callBeforeUpdateHook(ctx context.Context, v reflect.Value) (context.Context, error) { + return v.Interface().(BeforeUpdateHook).BeforeUpdate(ctx) +} + +func callBeforeUpdateHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) (context.Context, error) { + return callHookSlice(ctx, slice, ptr, callBeforeUpdateHook) +} + +//------------------------------------------------------------------------------ + +type AfterUpdateHook interface { + AfterUpdate(context.Context) error +} + +var afterUpdateHookType = reflect.TypeOf((*AfterUpdateHook)(nil)).Elem() + +func callAfterUpdateHook(ctx context.Context, v reflect.Value) error { + return v.Interface().(AfterUpdateHook).AfterUpdate(ctx) +} + +func callAfterUpdateHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) error { + return callHookSlice2(ctx, slice, ptr, callAfterUpdateHook) +} + +//------------------------------------------------------------------------------ + +type BeforeDeleteHook interface { + BeforeDelete(context.Context) (context.Context, error) +} + +var beforeDeleteHookType = reflect.TypeOf((*BeforeDeleteHook)(nil)).Elem() + +func callBeforeDeleteHook(ctx context.Context, v reflect.Value) (context.Context, error) { + return v.Interface().(BeforeDeleteHook).BeforeDelete(ctx) +} + +func callBeforeDeleteHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) (context.Context, error) { + return callHookSlice(ctx, slice, ptr, callBeforeDeleteHook) +} + +//------------------------------------------------------------------------------ + +type AfterDeleteHook interface { + AfterDelete(context.Context) error +} + +var afterDeleteHookType = reflect.TypeOf((*AfterDeleteHook)(nil)).Elem() + +func callAfterDeleteHook(ctx context.Context, v reflect.Value) error { + return v.Interface().(AfterDeleteHook).AfterDelete(ctx) +} + +func callAfterDeleteHookSlice( + ctx context.Context, slice reflect.Value, ptr bool, +) error { + return callHookSlice2(ctx, slice, ptr, callAfterDeleteHook) +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/insert.go b/vendor/github.com/go-pg/pg/v10/orm/insert.go new file mode 100644 index 000000000..a7a543576 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/insert.go @@ -0,0 +1,345 @@ +package orm + +import ( + "fmt" + "reflect" + "sort" + + "github.com/go-pg/pg/v10/types" +) + +type InsertQuery struct { + q *Query + returningFields []*Field + placeholder bool +} + +var _ QueryCommand = (*InsertQuery)(nil) + +func NewInsertQuery(q *Query) *InsertQuery { + return &InsertQuery{ + q: q, + } +} + +func (q *InsertQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *InsertQuery) Operation() QueryOp { + return InsertOp +} + +func (q *InsertQuery) Clone() QueryCommand { + return &InsertQuery{ + q: q.q.Clone(), + placeholder: q.placeholder, + } +} + +func (q *InsertQuery) Query() *Query { + return q.q +} + +var _ TemplateAppender = (*InsertQuery)(nil) + +func (q *InsertQuery) AppendTemplate(b []byte) ([]byte, error) { + cp := q.Clone().(*InsertQuery) + cp.placeholder = true + return cp.AppendQuery(dummyFormatter{}, b) +} + +var _ QueryAppender = (*InsertQuery)(nil) + +func (q *InsertQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + + if len(q.q.with) > 0 { + b, err = q.q.appendWith(fmter, b) + if err != nil { + return nil, err + } + } + + b = append(b, "INSERT INTO "...) + if q.q.onConflict != nil { + b, err = q.q.appendFirstTableWithAlias(fmter, b) + } else { + b, err = q.q.appendFirstTable(fmter, b) + } + if err != nil { + return nil, err + } + + b, err = q.appendColumnsValues(fmter, b) + if err != nil { + return nil, err + } + + if q.q.onConflict != nil { + b = append(b, " ON CONFLICT "...) + b, err = q.q.onConflict.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + + if q.q.onConflictDoUpdate() { + if len(q.q.set) > 0 { + b, err = q.q.appendSet(fmter, b) + if err != nil { + return nil, err + } + } else { + fields, err := q.q.getDataFields() + if err != nil { + return nil, err + } + + if len(fields) == 0 { + fields = q.q.tableModel.Table().DataFields + } + + b = q.appendSetExcluded(b, fields) + } + + if len(q.q.updWhere) > 0 { + b = append(b, " WHERE "...) + b, err = q.q.appendUpdWhere(fmter, b) + if err != nil { + return nil, err + } + } + } + } + + if len(q.q.returning) > 0 { + b, err = q.q.appendReturning(fmter, b) + if err != nil { + return nil, err + } + } else if len(q.returningFields) > 0 { + b = appendReturningFields(b, q.returningFields) + } + + return b, q.q.stickyErr +} + +func (q *InsertQuery) appendColumnsValues(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.q.hasMultiTables() { + if q.q.columns != nil { + b = append(b, " ("...) + b, err = q.q.appendColumns(fmter, b) + if err != nil { + return nil, err + } + b = append(b, ")"...) + } + + b = append(b, " SELECT * FROM "...) + b, err = q.q.appendOtherTables(fmter, b) + if err != nil { + return nil, err + } + + return b, nil + } + + if m, ok := q.q.model.(*mapModel); ok { + return q.appendMapColumnsValues(b, m.m), nil + } + + if !q.q.hasTableModel() { + return nil, errModelNil + } + + fields, err := q.q.getFields() + if err != nil { + return nil, err + } + + if len(fields) == 0 { + fields = q.q.tableModel.Table().Fields + } + value := q.q.tableModel.Value() + + b = append(b, " ("...) + b = q.appendColumns(b, fields) + b = append(b, ") VALUES ("...) + if m, ok := q.q.tableModel.(*sliceTableModel); ok { + if m.sliceLen == 0 { + err = fmt.Errorf("pg: can't bulk-insert empty slice %s", value.Type()) + return nil, err + } + b, err = q.appendSliceValues(fmter, b, fields, value) + if err != nil { + return nil, err + } + } else { + b, err = q.appendValues(fmter, b, fields, value) + if err != nil { + return nil, err + } + } + b = append(b, ")"...) + + return b, nil +} + +func (q *InsertQuery) appendMapColumnsValues(b []byte, m map[string]interface{}) []byte { + keys := make([]string, 0, len(m)) + + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + b = append(b, " ("...) + + for i, k := range keys { + if i > 0 { + b = append(b, ", "...) + } + b = types.AppendIdent(b, k, 1) + } + + b = append(b, ") VALUES ("...) + + for i, k := range keys { + if i > 0 { + b = append(b, ", "...) + } + if q.placeholder { + b = append(b, '?') + } else { + b = types.Append(b, m[k], 1) + } + } + + b = append(b, ")"...) + + return b +} + +func (q *InsertQuery) appendValues( + fmter QueryFormatter, b []byte, fields []*Field, strct reflect.Value, +) (_ []byte, err error) { + for i, f := range fields { + if i > 0 { + b = append(b, ", "...) + } + + app, ok := q.q.modelValues[f.SQLName] + if ok { + b, err = app.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + q.addReturningField(f) + continue + } + + switch { + case q.placeholder: + b = append(b, '?') + case (f.Default != "" || f.NullZero()) && f.HasZeroValue(strct): + b = append(b, "DEFAULT"...) + q.addReturningField(f) + default: + b = f.AppendValue(b, strct, 1) + } + } + + for i, v := range q.q.extraValues { + if i > 0 || len(fields) > 0 { + b = append(b, ", "...) + } + + b, err = v.value.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + + return b, nil +} + +func (q *InsertQuery) appendSliceValues( + fmter QueryFormatter, b []byte, fields []*Field, slice reflect.Value, +) (_ []byte, err error) { + if q.placeholder { + return q.appendValues(fmter, b, fields, reflect.Value{}) + } + + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + if i > 0 { + b = append(b, "), ("...) + } + el := indirect(slice.Index(i)) + b, err = q.appendValues(fmter, b, fields, el) + if err != nil { + return nil, err + } + } + + for i, v := range q.q.extraValues { + if i > 0 || len(fields) > 0 { + b = append(b, ", "...) + } + + b, err = v.value.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + + return b, nil +} + +func (q *InsertQuery) addReturningField(field *Field) { + if len(q.q.returning) > 0 { + return + } + for _, f := range q.returningFields { + if f == field { + return + } + } + q.returningFields = append(q.returningFields, field) +} + +func (q *InsertQuery) appendSetExcluded(b []byte, fields []*Field) []byte { + b = append(b, " SET "...) + for i, f := range fields { + if i > 0 { + b = append(b, ", "...) + } + b = append(b, f.Column...) + b = append(b, " = EXCLUDED."...) + b = append(b, f.Column...) + } + return b +} + +func (q *InsertQuery) appendColumns(b []byte, fields []*Field) []byte { + b = appendColumns(b, "", fields) + for i, v := range q.q.extraValues { + if i > 0 || len(fields) > 0 { + b = append(b, ", "...) + } + b = types.AppendIdent(b, v.column, 1) + } + return b +} + +func appendReturningFields(b []byte, fields []*Field) []byte { + b = append(b, " RETURNING "...) + b = appendColumns(b, "", fields) + return b +} diff --git a/vendor/github.com/go-pg/pg/orm/join.go b/vendor/github.com/go-pg/pg/v10/orm/join.go similarity index 63% rename from vendor/github.com/go-pg/pg/orm/join.go rename to vendor/github.com/go-pg/pg/v10/orm/join.go index f7c3a99e4..2b64ba1b8 100644 --- a/vendor/github.com/go-pg/pg/orm/join.go +++ b/vendor/github.com/go-pg/pg/v10/orm/join.go @@ -3,14 +3,14 @@ package orm import ( "reflect" - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/types" + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/types" ) type join struct { Parent *join - BaseModel tableModel - JoinModel tableModel + BaseModel TableModel + JoinModel TableModel Rel *Relation ApplyQuery func(*Query) (*Query, error) @@ -22,17 +22,17 @@ func (j *join) AppendOn(app *condAppender) { j.on = append(j.on, app) } -func (j *join) Select(q *Query) error { +func (j *join) Select(fmter QueryFormatter, q *Query) error { switch j.Rel.Type { case HasManyRelation: - return j.selectMany(q) + return j.selectMany(fmter, q) case Many2ManyRelation: - return j.selectM2M(q) + return j.selectM2M(fmter, q) } panic("not reached") } -func (j *join) selectMany(q *Query) error { +func (j *join) selectMany(_ QueryFormatter, q *Query) error { q, err := j.manyQuery(q) if err != nil { return err @@ -59,21 +59,21 @@ func (j *join) manyQuery(q *Query) (*Query, error) { } if len(q.columns) == 0 { - q.columns = append(q.columns, hasManyColumnsAppender{j}) + q.columns = append(q.columns, &hasManyColumnsAppender{j}) } baseTable := j.BaseModel.Table() var where []byte - if len(j.Rel.FKs) > 1 { + if len(j.Rel.JoinFKs) > 1 { where = append(where, '(') } - where = appendColumns(where, j.JoinModel.Table().Alias, j.Rel.FKs) - if len(j.Rel.FKs) > 1 { - where = append(where, '(') + where = appendColumns(where, j.JoinModel.Table().Alias, j.Rel.JoinFKs) + if len(j.Rel.JoinFKs) > 1 { + where = append(where, ')') } where = append(where, " IN ("...) where = appendChildValues( - where, j.JoinModel.Root(), j.JoinModel.ParentIndex(), j.Rel.FKValues) + where, j.JoinModel.Root(), j.JoinModel.ParentIndex(), j.Rel.BaseFKs) where = append(where, ")"...) q = q.Where(internal.BytesToString(where)) @@ -86,8 +86,8 @@ func (j *join) manyQuery(q *Query) (*Query, error) { return q, nil } -func (j *join) selectM2M(q *Query) error { - q, err := j.m2mQuery(q) +func (j *join) selectM2M(fmter QueryFormatter, q *Query) error { + q, err := j.m2mQuery(fmter, q) if err != nil { return err } @@ -97,7 +97,7 @@ func (j *join) selectM2M(q *Query) error { return q.Select() } -func (j *join) m2mQuery(q *Query) (*Query, error) { +func (j *join) m2mQuery(fmter QueryFormatter, q *Query) (*Query, error) { m2mModel := newM2MModel(j) if m2mModel == nil { return nil, nil @@ -113,24 +113,26 @@ func (j *join) m2mQuery(q *Query) (*Query, error) { } if len(q.columns) == 0 { - q.columns = append(q.columns, hasManyColumnsAppender{j}) + q.columns = append(q.columns, &hasManyColumnsAppender{j}) } index := j.JoinModel.ParentIndex() baseTable := j.BaseModel.Table() + + //nolint var join []byte join = append(join, "JOIN "...) - join = q.FormatQuery(join, string(j.Rel.M2MTableName)) + join = fmter.FormatQuery(join, string(j.Rel.M2MTableName)) join = append(join, " AS "...) join = append(join, j.Rel.M2MTableAlias...) join = append(join, " ON ("...) - for i, col := range j.Rel.BaseFKs { + for i, col := range j.Rel.M2MBaseFKs { if i > 0 { join = append(join, ", "...) } join = append(join, j.Rel.M2MTableAlias...) join = append(join, '.') - join = types.AppendField(join, col, 1) + join = types.AppendIdent(join, col, 1) } join = append(join, ") IN ("...) join = appendChildValues(join, j.BaseModel.Root(), index, baseTable.PKs) @@ -138,14 +140,11 @@ func (j *join) m2mQuery(q *Query) (*Query, error) { q = q.Join(internal.BytesToString(join)) joinTable := j.JoinModel.Table() - for i, col := range j.Rel.JoinFKs { - if i >= len(joinTable.PKs) { - break - } + for i, col := range j.Rel.M2MJoinFKs { pk := joinTable.PKs[i] q = q.Where("?.? = ?.?", joinTable.Alias, pk.Column, - j.Rel.M2MTableAlias, types.F(col)) + j.Rel.M2MTableAlias, types.Ident(col)) } return q, nil @@ -163,16 +162,16 @@ func (j *join) hasParent() bool { func (j *join) appendAlias(b []byte) []byte { b = append(b, '"') - b = appendAlias(b, j, true) + b = appendAlias(b, j) b = append(b, '"') return b } func (j *join) appendAliasColumn(b []byte, column string) []byte { b = append(b, '"') - b = appendAlias(b, j, true) + b = appendAlias(b, j) b = append(b, "__"...) - b = types.AppendField(b, column, 2) + b = append(b, column...) b = append(b, '"') return b } @@ -180,19 +179,27 @@ func (j *join) appendAliasColumn(b []byte, column string) []byte { func (j *join) appendBaseAlias(b []byte) []byte { if j.hasParent() { b = append(b, '"') - b = appendAlias(b, j.Parent, true) + b = appendAlias(b, j.Parent) b = append(b, '"') return b } return append(b, j.BaseModel.Table().Alias...) } -func appendAlias(b []byte, j *join, topLevel bool) []byte { - if j.hasParent() { - b = appendAlias(b, j.Parent, topLevel) - topLevel = false +func (j *join) appendSoftDelete(b []byte, flags queryFlag) []byte { + b = append(b, '.') + b = append(b, j.JoinModel.Table().SoftDeleteField.Column...) + if hasFlag(flags, deletedFlag) { + b = append(b, " IS NOT NULL"...) + } else { + b = append(b, " IS NULL"...) } - if !topLevel { + return b +} + +func appendAlias(b []byte, j *join) []byte { + if j.hasParent() { + b = appendAlias(b, j.Parent) b = append(b, "__"...) } b = append(b, j.Rel.Field.SQLName...) @@ -220,7 +227,7 @@ func (j *join) appendHasOneColumns(b []byte) []byte { } b = j.appendAlias(b) b = append(b, '.') - b = types.AppendField(b, column, 1) + b = types.AppendIdent(b, column, 1) b = append(b, " AS "...) b = j.appendAliasColumn(b, column) } @@ -228,69 +235,67 @@ func (j *join) appendHasOneColumns(b []byte) []byte { return b } -func (j *join) appendHasOneJoin(q *Query, b []byte) []byte { +func (j *join) appendHasOneJoin(fmter QueryFormatter, b []byte, q *Query) (_ []byte, err error) { + isSoftDelete := j.JoinModel.Table().SoftDeleteField != nil && !q.hasFlag(allWithDeletedFlag) + b = append(b, "LEFT JOIN "...) - b = q.FormatQuery(b, string(j.JoinModel.Table().NameForSelects)) + b = fmter.FormatQuery(b, string(j.JoinModel.Table().SQLNameForSelects)) b = append(b, " AS "...) b = j.appendAlias(b) b = append(b, " ON "...) - if len(j.Rel.FKs) > 1 { + if isSoftDelete { b = append(b, '(') } - if j.Rel.Type == HasOneRelation { - joinTable := j.Rel.JoinTable - for i, fk := range j.Rel.FKs { - if i > 0 { - b = append(b, " AND "...) - } - b = j.appendAlias(b) - b = append(b, '.') - b = append(b, joinTable.PKs[i].Column...) - b = append(b, " = "...) - b = j.appendBaseAlias(b) - b = append(b, '.') - b = append(b, fk.Column...) - } - } else { - baseTable := j.BaseModel.Table() - for i, fk := range j.Rel.FKs { - if i > 0 { - b = append(b, " AND "...) - } - b = j.appendAlias(b) - b = append(b, '.') - b = append(b, fk.Column...) - b = append(b, " = "...) - b = j.appendBaseAlias(b) - b = append(b, '.') - b = append(b, baseTable.PKs[i].Column...) + + if len(j.Rel.BaseFKs) > 1 { + b = append(b, '(') + } + for i, baseFK := range j.Rel.BaseFKs { + if i > 0 { + b = append(b, " AND "...) } + b = j.appendAlias(b) + b = append(b, '.') + b = append(b, j.Rel.JoinFKs[i].Column...) + b = append(b, " = "...) + b = j.appendBaseAlias(b) + b = append(b, '.') + b = append(b, baseFK.Column...) } - if len(j.Rel.FKs) > 1 { + if len(j.Rel.BaseFKs) > 1 { b = append(b, ')') } for _, on := range j.on { b = on.AppendSep(b) - b = on.AppendFormat(b, q) + b, err = on.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + + if isSoftDelete { + b = append(b, ')') } - if q.softDelete() { + if isSoftDelete { b = append(b, " AND "...) - b = j.appendBaseAlias(b) - b = q.appendSoftDelete(b) + b = j.appendAlias(b) + b = j.appendSoftDelete(b, q.flags) } - return b + return b, nil } type hasManyColumnsAppender struct { *join } -func (q hasManyColumnsAppender) AppendFormat(b []byte, f QueryFormatter) []byte { +var _ QueryAppender = (*hasManyColumnsAppender)(nil) + +func (q *hasManyColumnsAppender) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { if q.Rel.M2MTableAlias != "" { b = append(b, q.Rel.M2MTableAlias...) b = append(b, ".*, "...) @@ -305,12 +310,13 @@ func (q hasManyColumnsAppender) AppendFormat(b []byte, f QueryFormatter) []byte } b = append(b, joinTable.Alias...) b = append(b, '.') - b = types.AppendField(b, column, 1) + b = types.AppendIdent(b, column, 1) } - return b + return b, nil } - return appendColumns(b, joinTable.Alias, joinTable.Fields) + b = appendColumns(b, joinTable.Alias, joinTable.Fields) + return b, nil } func appendChildValues(b []byte, v reflect.Value, index []int, fields []*Field) []byte { diff --git a/vendor/github.com/go-pg/pg/v10/orm/model.go b/vendor/github.com/go-pg/pg/v10/orm/model.go new file mode 100644 index 000000000..333a90dd7 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model.go @@ -0,0 +1,150 @@ +package orm + +import ( + "database/sql" + "errors" + "fmt" + "reflect" + + "github.com/go-pg/pg/v10/types" +) + +var errModelNil = errors.New("pg: Model(nil)") + +type useQueryOne interface { + useQueryOne() bool +} + +type HooklessModel interface { + // Init is responsible to initialize/reset model state. + // It is called only once no matter how many rows were returned. + Init() error + + // NextColumnScanner returns a ColumnScanner that is used to scan columns + // from the current row. It is called once for every row. + NextColumnScanner() ColumnScanner + + // AddColumnScanner adds the ColumnScanner to the model. + AddColumnScanner(ColumnScanner) error +} + +type Model interface { + HooklessModel + + AfterScanHook + AfterSelectHook + + BeforeInsertHook + AfterInsertHook + + BeforeUpdateHook + AfterUpdateHook + + BeforeDeleteHook + AfterDeleteHook +} + +func NewModel(value interface{}) (Model, error) { + return newModel(value, false) +} + +func newScanModel(values []interface{}) (Model, error) { + if len(values) > 1 { + return Scan(values...), nil + } + return newModel(values[0], true) +} + +func newModel(value interface{}, scan bool) (Model, error) { + switch value := value.(type) { + case Model: + return value, nil + case HooklessModel: + return newModelWithHookStubs(value), nil + case types.ValueScanner, sql.Scanner: + if !scan { + return nil, fmt.Errorf("pg: Model(unsupported %T)", value) + } + return Scan(value), nil + } + + v := reflect.ValueOf(value) + if !v.IsValid() { + return nil, errModelNil + } + if v.Kind() != reflect.Ptr { + return nil, fmt.Errorf("pg: Model(non-pointer %T)", value) + } + + if v.IsNil() { + typ := v.Type().Elem() + if typ.Kind() == reflect.Struct { + return newStructTableModel(GetTable(typ)), nil + } + return nil, errModelNil + } + + v = v.Elem() + + if v.Kind() == reflect.Interface { + if !v.IsNil() { + v = v.Elem() + if v.Kind() != reflect.Ptr { + return nil, fmt.Errorf("pg: Model(non-pointer %s)", v.Type().String()) + } + } + } + + switch v.Kind() { + case reflect.Struct: + if v.Type() != timeType { + return newStructTableModelValue(v), nil + } + case reflect.Slice: + elemType := sliceElemType(v) + switch elemType.Kind() { + case reflect.Struct: + if elemType != timeType { + return newSliceTableModel(v, elemType), nil + } + case reflect.Map: + if err := validMap(elemType); err != nil { + return nil, err + } + slicePtr := v.Addr().Interface().(*[]map[string]interface{}) + return newMapSliceModel(slicePtr), nil + } + return newSliceModel(v, elemType), nil + case reflect.Map: + typ := v.Type() + if err := validMap(typ); err != nil { + return nil, err + } + mapPtr := v.Addr().Interface().(*map[string]interface{}) + return newMapModel(mapPtr), nil + } + + if !scan { + return nil, fmt.Errorf("pg: Model(unsupported %T)", value) + } + return Scan(value), nil +} + +type modelWithHookStubs struct { + hookStubs + HooklessModel +} + +func newModelWithHookStubs(m HooklessModel) Model { + return modelWithHookStubs{ + HooklessModel: m, + } +} + +func validMap(typ reflect.Type) error { + if typ.Key().Kind() != reflect.String || typ.Elem().Kind() != reflect.Interface { + return fmt.Errorf("pg: Model(unsupported %s, expected *map[string]interface{})", + typ.String()) + } + return nil +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_discard.go b/vendor/github.com/go-pg/pg/v10/orm/model_discard.go new file mode 100644 index 000000000..92e5c566c --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_discard.go @@ -0,0 +1,27 @@ +package orm + +import ( + "github.com/go-pg/pg/v10/types" +) + +type Discard struct { + hookStubs +} + +var _ Model = (*Discard)(nil) + +func (Discard) Init() error { + return nil +} + +func (m Discard) NextColumnScanner() ColumnScanner { + return m +} + +func (m Discard) AddColumnScanner(ColumnScanner) error { + return nil +} + +func (m Discard) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + return nil +} diff --git a/vendor/github.com/go-pg/pg/orm/model_func.go b/vendor/github.com/go-pg/pg/v10/orm/model_func.go similarity index 91% rename from vendor/github.com/go-pg/pg/orm/model_func.go rename to vendor/github.com/go-pg/pg/v10/orm/model_func.go index 64b300b7c..8427bdea2 100644 --- a/vendor/github.com/go-pg/pg/orm/model_func.go +++ b/vendor/github.com/go-pg/pg/v10/orm/model_func.go @@ -31,7 +31,7 @@ func newFuncModel(fn interface{}) *funcModel { } if fnt.NumOut() != 1 { - panic(fmt.Errorf("ForEach must return 1 value, got %d", fnt.NumOut())) + panic(fmt.Errorf("ForEach must return 1 error value, got %d", fnt.NumOut())) } if fnt.Out(0) != errorType { panic(fmt.Errorf("ForEach must return an error, got %T", fnt.Out(0))) @@ -79,7 +79,7 @@ func initFuncModelScan(m *funcModel, fnt reflect.Type) { m.Model = scanReflectValues(m.fnIn) } -func (m *funcModel) AddModel(_ ColumnScanner) error { +func (m *funcModel) AddColumnScanner(_ ColumnScanner) error { out := m.fnv.Call(m.fnIn) errv := out[0] if !errv.IsNil() { diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_map.go b/vendor/github.com/go-pg/pg/v10/orm/model_map.go new file mode 100644 index 000000000..24533d43c --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_map.go @@ -0,0 +1,53 @@ +package orm + +import ( + "github.com/go-pg/pg/v10/types" +) + +type mapModel struct { + hookStubs + ptr *map[string]interface{} + m map[string]interface{} +} + +var _ Model = (*mapModel)(nil) + +func newMapModel(ptr *map[string]interface{}) *mapModel { + model := &mapModel{ + ptr: ptr, + } + if ptr != nil { + model.m = *ptr + } + return model +} + +func (m *mapModel) Init() error { + return nil +} + +func (m *mapModel) NextColumnScanner() ColumnScanner { + if m.m == nil { + m.m = make(map[string]interface{}) + *m.ptr = m.m + } + return m +} + +func (m mapModel) AddColumnScanner(ColumnScanner) error { + return nil +} + +func (m *mapModel) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + val, err := types.ReadColumnValue(col, rd, n) + if err != nil { + return err + } + + m.m[col.Name] = val + return nil +} + +func (mapModel) useQueryOne() bool { + return true +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_map_slice.go b/vendor/github.com/go-pg/pg/v10/orm/model_map_slice.go new file mode 100644 index 000000000..ea14c9b6b --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_map_slice.go @@ -0,0 +1,45 @@ +package orm + +type mapSliceModel struct { + mapModel + slice *[]map[string]interface{} +} + +var _ Model = (*mapSliceModel)(nil) + +func newMapSliceModel(ptr *[]map[string]interface{}) *mapSliceModel { + return &mapSliceModel{ + slice: ptr, + } +} + +func (m *mapSliceModel) Init() error { + slice := *m.slice + if len(slice) > 0 { + *m.slice = slice[:0] + } + return nil +} + +func (m *mapSliceModel) NextColumnScanner() ColumnScanner { + slice := *m.slice + if len(slice) == cap(slice) { + m.mapModel.m = make(map[string]interface{}) + *m.slice = append(slice, m.mapModel.m) //nolint:gocritic + return m + } + + slice = slice[:len(slice)+1] + el := slice[len(slice)-1] + if el != nil { + m.mapModel.m = el + } else { + el = make(map[string]interface{}) + slice[len(slice)-1] = el + m.mapModel.m = el + } + *m.slice = slice + return m +} + +func (mapSliceModel) useQueryOne() {} //nolint:unused diff --git a/vendor/github.com/go-pg/pg/orm/model_scan.go b/vendor/github.com/go-pg/pg/v10/orm/model_scan.go similarity index 59% rename from vendor/github.com/go-pg/pg/orm/model_scan.go rename to vendor/github.com/go-pg/pg/v10/orm/model_scan.go index 6874b736b..08f66beba 100644 --- a/vendor/github.com/go-pg/pg/orm/model_scan.go +++ b/vendor/github.com/go-pg/pg/v10/orm/model_scan.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - "github.com/go-pg/pg/types" + "github.com/go-pg/pg/v10/types" ) type scanValuesModel struct { @@ -14,6 +14,7 @@ type scanValuesModel struct { var _ Model = scanValuesModel{} +//nolint func Scan(values ...interface{}) scanValuesModel { return scanValuesModel{ values: values, @@ -24,16 +25,16 @@ func (scanValuesModel) useQueryOne() bool { return true } -func (m scanValuesModel) NewModel() ColumnScanner { +func (m scanValuesModel) NextColumnScanner() ColumnScanner { return m } -func (m scanValuesModel) ScanColumn(colIdx int, colName string, b []byte) error { - if colIdx >= len(m.values) { +func (m scanValuesModel) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + if int(col.Index) >= len(m.values) { return fmt.Errorf("pg: no Scan var for column index=%d name=%q", - colIdx, colName) + col.Index, col.Name) } - return types.Scan(m.values[colIdx], b) + return types.Scan(m.values[col.Index], rd, n) } //------------------------------------------------------------------------------ @@ -55,14 +56,14 @@ func (scanReflectValuesModel) useQueryOne() bool { return true } -func (m scanReflectValuesModel) NewModel() ColumnScanner { +func (m scanReflectValuesModel) NextColumnScanner() ColumnScanner { return m } -func (m scanReflectValuesModel) ScanColumn(colIdx int, colName string, b []byte) error { - if colIdx >= len(m.values) { +func (m scanReflectValuesModel) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + if int(col.Index) >= len(m.values) { return fmt.Errorf("pg: no Scan var for column index=%d name=%q", - colIdx, colName) + col.Index, col.Name) } - return types.ScanValue(m.values[colIdx], b) + return types.ScanValue(m.values[col.Index], rd, n) } diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_slice.go b/vendor/github.com/go-pg/pg/v10/orm/model_slice.go new file mode 100644 index 000000000..1e163629e --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_slice.go @@ -0,0 +1,43 @@ +package orm + +import ( + "reflect" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/types" +) + +type sliceModel struct { + Discard + slice reflect.Value + nextElem func() reflect.Value + scan func(reflect.Value, types.Reader, int) error +} + +var _ Model = (*sliceModel)(nil) + +func newSliceModel(slice reflect.Value, elemType reflect.Type) *sliceModel { + return &sliceModel{ + slice: slice, + scan: types.Scanner(elemType), + } +} + +func (m *sliceModel) Init() error { + if m.slice.IsValid() && m.slice.Len() > 0 { + m.slice.Set(m.slice.Slice(0, 0)) + } + return nil +} + +func (m *sliceModel) NextColumnScanner() ColumnScanner { + return m +} + +func (m *sliceModel) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + if m.nextElem == nil { + m.nextElem = internal.MakeSliceNextElemFunc(m.slice) + } + v := m.nextElem() + return m.scan(v, rd, n) +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_table.go b/vendor/github.com/go-pg/pg/v10/orm/model_table.go new file mode 100644 index 000000000..afdc15ccc --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_table.go @@ -0,0 +1,65 @@ +package orm + +import ( + "fmt" + "reflect" + + "github.com/go-pg/pg/v10/types" +) + +type TableModel interface { + Model + + IsNil() bool + Table() *Table + Relation() *Relation + AppendParam(QueryFormatter, []byte, string) ([]byte, bool) + + Join(string, func(*Query) (*Query, error)) *join + GetJoin(string) *join + GetJoins() []join + AddJoin(join) *join + + Root() reflect.Value + Index() []int + ParentIndex() []int + Mount(reflect.Value) + Kind() reflect.Kind + Value() reflect.Value + + setSoftDeleteField() error + scanColumn(types.ColumnInfo, types.Reader, int) (bool, error) +} + +func newTableModelIndex(typ reflect.Type, root reflect.Value, index []int, rel *Relation) (TableModel, error) { + typ = typeByIndex(typ, index) + + if typ.Kind() == reflect.Struct { + return &structTableModel{ + table: GetTable(typ), + rel: rel, + + root: root, + index: index, + }, nil + } + + if typ.Kind() == reflect.Slice { + structType := indirectType(typ.Elem()) + if structType.Kind() == reflect.Struct { + m := sliceTableModel{ + structTableModel: structTableModel{ + table: GetTable(structType), + rel: rel, + + root: root, + index: index, + }, + } + m.init(typ) + return &m, nil + } + } + + return nil, fmt.Errorf("pg: NewModel(%s)", typ) +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_table_m2m.go b/vendor/github.com/go-pg/pg/v10/orm/model_table_m2m.go new file mode 100644 index 000000000..83ac73bde --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_table_m2m.go @@ -0,0 +1,111 @@ +package orm + +import ( + "fmt" + "reflect" + + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/types" +) + +type m2mModel struct { + *sliceTableModel + baseTable *Table + rel *Relation + + buf []byte + dstValues map[string][]reflect.Value + columns map[string]string +} + +var _ TableModel = (*m2mModel)(nil) + +func newM2MModel(j *join) *m2mModel { + baseTable := j.BaseModel.Table() + joinModel := j.JoinModel.(*sliceTableModel) + dstValues := dstValues(joinModel, baseTable.PKs) + if len(dstValues) == 0 { + return nil + } + m := &m2mModel{ + sliceTableModel: joinModel, + baseTable: baseTable, + rel: j.Rel, + + dstValues: dstValues, + columns: make(map[string]string), + } + if !m.sliceOfPtr { + m.strct = reflect.New(m.table.Type).Elem() + } + return m +} + +func (m *m2mModel) NextColumnScanner() ColumnScanner { + if m.sliceOfPtr { + m.strct = reflect.New(m.table.Type).Elem() + } else { + m.strct.Set(m.table.zeroStruct) + } + m.structInited = false + return m +} + +func (m *m2mModel) AddColumnScanner(_ ColumnScanner) error { + buf, err := m.modelIDMap(m.buf[:0]) + if err != nil { + return err + } + m.buf = buf + + dstValues, ok := m.dstValues[string(buf)] + if !ok { + return fmt.Errorf( + "pg: relation=%q does not have base %s with id=%q (check join conditions)", + m.rel.Field.GoName, m.baseTable, buf) + } + + for _, v := range dstValues { + if m.sliceOfPtr { + v.Set(reflect.Append(v, m.strct.Addr())) + } else { + v.Set(reflect.Append(v, m.strct)) + } + } + + return nil +} + +func (m *m2mModel) modelIDMap(b []byte) ([]byte, error) { + for i, col := range m.rel.M2MBaseFKs { + if i > 0 { + b = append(b, ',') + } + if s, ok := m.columns[col]; ok { + b = append(b, s...) + } else { + return nil, fmt.Errorf("pg: %s does not have column=%q", + m.sliceTableModel, col) + } + } + return b, nil +} + +func (m *m2mModel) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + if n > 0 { + b, err := rd.ReadFullTemp() + if err != nil { + return err + } + + m.columns[col.Name] = string(b) + rd = pool.NewBytesReader(b) + } else { + m.columns[col.Name] = "" + } + + if ok, err := m.sliceTableModel.scanColumn(col, rd, n); ok { + return err + } + return nil +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_table_many.go b/vendor/github.com/go-pg/pg/v10/orm/model_table_many.go new file mode 100644 index 000000000..561384bba --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_table_many.go @@ -0,0 +1,75 @@ +package orm + +import ( + "fmt" + "reflect" +) + +type manyModel struct { + *sliceTableModel + baseTable *Table + rel *Relation + + buf []byte + dstValues map[string][]reflect.Value +} + +var _ TableModel = (*manyModel)(nil) + +func newManyModel(j *join) *manyModel { + baseTable := j.BaseModel.Table() + joinModel := j.JoinModel.(*sliceTableModel) + dstValues := dstValues(joinModel, j.Rel.BaseFKs) + if len(dstValues) == 0 { + return nil + } + m := manyModel{ + sliceTableModel: joinModel, + baseTable: baseTable, + rel: j.Rel, + + dstValues: dstValues, + } + if !m.sliceOfPtr { + m.strct = reflect.New(m.table.Type).Elem() + } + return &m +} + +func (m *manyModel) NextColumnScanner() ColumnScanner { + if m.sliceOfPtr { + m.strct = reflect.New(m.table.Type).Elem() + } else { + m.strct.Set(m.table.zeroStruct) + } + m.structInited = false + return m +} + +func (m *manyModel) AddColumnScanner(model ColumnScanner) error { + m.buf = modelID(m.buf[:0], m.strct, m.rel.JoinFKs) + dstValues, ok := m.dstValues[string(m.buf)] + if !ok { + return fmt.Errorf( + "pg: relation=%q does not have base %s with id=%q (check join conditions)", + m.rel.Field.GoName, m.baseTable, m.buf) + } + + for i, v := range dstValues { + if !m.sliceOfPtr { + v.Set(reflect.Append(v, m.strct)) + continue + } + + if i == 0 { + v.Set(reflect.Append(v, m.strct.Addr())) + continue + } + + clone := reflect.New(m.strct.Type()).Elem() + clone.Set(m.strct) + v.Set(reflect.Append(v, clone.Addr())) + } + + return nil +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/model_table_slice.go b/vendor/github.com/go-pg/pg/v10/orm/model_table_slice.go new file mode 100644 index 000000000..c50be8252 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/model_table_slice.go @@ -0,0 +1,156 @@ +package orm + +import ( + "context" + "reflect" + + "github.com/go-pg/pg/v10/internal" +) + +type sliceTableModel struct { + structTableModel + + slice reflect.Value + sliceLen int + sliceOfPtr bool + nextElem func() reflect.Value +} + +var _ TableModel = (*sliceTableModel)(nil) + +func newSliceTableModel(slice reflect.Value, elemType reflect.Type) *sliceTableModel { + m := &sliceTableModel{ + structTableModel: structTableModel{ + table: GetTable(elemType), + root: slice, + }, + slice: slice, + sliceLen: slice.Len(), + nextElem: internal.MakeSliceNextElemFunc(slice), + } + m.init(slice.Type()) + return m +} + +func (m *sliceTableModel) init(sliceType reflect.Type) { + switch sliceType.Elem().Kind() { + case reflect.Ptr, reflect.Interface: + m.sliceOfPtr = true + } +} + +//nolint +func (*sliceTableModel) useQueryOne() {} + +func (m *sliceTableModel) IsNil() bool { + return false +} + +func (m *sliceTableModel) AppendParam(fmter QueryFormatter, b []byte, name string) ([]byte, bool) { + if field, ok := m.table.FieldsMap[name]; ok { + b = append(b, "_data."...) + b = append(b, field.Column...) + return b, true + } + return m.structTableModel.AppendParam(fmter, b, name) +} + +func (m *sliceTableModel) Join(name string, apply func(*Query) (*Query, error)) *join { + return m.join(m.Value(), name, apply) +} + +func (m *sliceTableModel) Bind(bind reflect.Value) { + m.slice = bind.Field(m.index[len(m.index)-1]) +} + +func (m *sliceTableModel) Kind() reflect.Kind { + return reflect.Slice +} + +func (m *sliceTableModel) Value() reflect.Value { + return m.slice +} + +func (m *sliceTableModel) Init() error { + if m.slice.IsValid() && m.slice.Len() > 0 { + m.slice.Set(m.slice.Slice(0, 0)) + } + return nil +} + +func (m *sliceTableModel) NextColumnScanner() ColumnScanner { + m.strct = m.nextElem() + m.structInited = false + return m +} + +func (m *sliceTableModel) AddColumnScanner(_ ColumnScanner) error { + return nil +} + +// Inherit these hooks from structTableModel. +var ( + _ BeforeScanHook = (*sliceTableModel)(nil) + _ AfterScanHook = (*sliceTableModel)(nil) +) + +func (m *sliceTableModel) AfterSelect(ctx context.Context) error { + if m.table.hasFlag(afterSelectHookFlag) { + return callAfterSelectHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return nil +} + +func (m *sliceTableModel) BeforeInsert(ctx context.Context) (context.Context, error) { + if m.table.hasFlag(beforeInsertHookFlag) { + return callBeforeInsertHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return ctx, nil +} + +func (m *sliceTableModel) AfterInsert(ctx context.Context) error { + if m.table.hasFlag(afterInsertHookFlag) { + return callAfterInsertHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return nil +} + +func (m *sliceTableModel) BeforeUpdate(ctx context.Context) (context.Context, error) { + if m.table.hasFlag(beforeUpdateHookFlag) && !m.IsNil() { + return callBeforeUpdateHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return ctx, nil +} + +func (m *sliceTableModel) AfterUpdate(ctx context.Context) error { + if m.table.hasFlag(afterUpdateHookFlag) { + return callAfterUpdateHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return nil +} + +func (m *sliceTableModel) BeforeDelete(ctx context.Context) (context.Context, error) { + if m.table.hasFlag(beforeDeleteHookFlag) && !m.IsNil() { + return callBeforeDeleteHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return ctx, nil +} + +func (m *sliceTableModel) AfterDelete(ctx context.Context) error { + if m.table.hasFlag(afterDeleteHookFlag) && !m.IsNil() { + return callAfterDeleteHookSlice(ctx, m.slice, m.sliceOfPtr) + } + return nil +} + +func (m *sliceTableModel) setSoftDeleteField() error { + sliceLen := m.slice.Len() + for i := 0; i < sliceLen; i++ { + strct := indirect(m.slice.Index(i)) + fv := m.table.SoftDeleteField.Value(strct) + if err := m.table.SetSoftDeleteField(fv); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/go-pg/pg/orm/model_table_struct.go b/vendor/github.com/go-pg/pg/v10/orm/model_table_struct.go similarity index 52% rename from vendor/github.com/go-pg/pg/orm/model_table_struct.go rename to vendor/github.com/go-pg/pg/v10/orm/model_table_struct.go index 44e77eb65..fce7cc6b7 100644 --- a/vendor/github.com/go-pg/pg/orm/model_table_struct.go +++ b/vendor/github.com/go-pg/pg/v10/orm/model_table_struct.go @@ -1,11 +1,12 @@ package orm import ( - "errors" + "context" "fmt" "reflect" "strings" - "time" + + "github.com/go-pg/pg/v10/types" ) type structTableModel struct { @@ -21,7 +22,13 @@ type structTableModel struct { structInitErr error } -var _ tableModel = (*structTableModel)(nil) +var _ TableModel = (*structTableModel)(nil) + +func newStructTableModel(table *Table) *structTableModel { + return &structTableModel{ + table: table, + } +} func newStructTableModelValue(v reflect.Value) *structTableModel { return &structTableModel{ @@ -31,14 +38,16 @@ func newStructTableModelValue(v reflect.Value) *structTableModel { } } -func newStructTableModelType(typ reflect.Type) *structTableModel { - return &structTableModel{ - table: GetTable(typ), - } +func (*structTableModel) useQueryOne() bool { + return true } -func (structTableModel) useQueryOne() bool { - return true +func (m *structTableModel) String() string { + return m.table.String() +} + +func (m *structTableModel) IsNil() bool { + return !m.strct.IsValid() } func (m *structTableModel) Table() *Table { @@ -49,7 +58,7 @@ func (m *structTableModel) Relation() *Relation { return m.rel } -func (m *structTableModel) AppendParam(b []byte, f QueryFormatter, name string) ([]byte, bool) { +func (m *structTableModel) AppendParam(fmter QueryFormatter, b []byte, name string) ([]byte, bool) { b, ok := m.table.AppendParam(b, m.strct, name) if ok { return b, true @@ -57,7 +66,7 @@ func (m *structTableModel) AppendParam(b []byte, f QueryFormatter, name string) switch name { case "TableName": - b = f.FormatQuery(b, string(m.table.Name)) + b = fmter.FormatQuery(b, string(m.table.SQLName)) return b, true case "TableAlias": b = append(b, m.table.Alias...) @@ -68,6 +77,12 @@ func (m *structTableModel) AppendParam(b []byte, f QueryFormatter, name string) case "Columns": b = appendColumns(b, "", m.table.Fields) return b, true + case "TablePKs": + b = appendColumns(b, m.table.Alias, m.table.PKs) + return b, true + case "PKs": + b = appendColumns(b, "", m.table.PKs) + return b, true } return b, false @@ -106,7 +121,7 @@ func (m *structTableModel) initStruct() error { switch m.strct.Kind() { case reflect.Invalid: - m.structInitErr = errors.New("pg: Model(nil)") + m.structInitErr = errModelNil return m.structInitErr case reflect.Interface: m.strct = m.strct.Elem() @@ -140,121 +155,147 @@ func (structTableModel) Init() error { return nil } -func (m *structTableModel) NewModel() ColumnScanner { +func (m *structTableModel) NextColumnScanner() ColumnScanner { return m } -func (m *structTableModel) AddModel(_ ColumnScanner) error { +func (m *structTableModel) AddColumnScanner(_ ColumnScanner) error { return nil } -func (m *structTableModel) AfterQuery(db DB) error { - if !m.table.HasFlag(AfterQueryHookFlag) { +var _ BeforeScanHook = (*structTableModel)(nil) + +func (m *structTableModel) BeforeScan(ctx context.Context) error { + if !m.table.hasFlag(beforeScanHookFlag) { return nil } - return callAfterQueryHook(m.strct.Addr(), db) + return callBeforeScanHook(ctx, m.strct.Addr()) } -func (m *structTableModel) BeforeSelectQuery(db DB, q *Query) (*Query, error) { - if !m.table.HasFlag(BeforeSelectQueryHookFlag) { - return q, nil +var _ AfterScanHook = (*structTableModel)(nil) + +func (m *structTableModel) AfterScan(ctx context.Context) error { + if !m.table.hasFlag(afterScanHookFlag) || !m.structInited { + return nil } - return callBeforeSelectQueryHook(m.table.zeroStruct.Addr(), db, q) + + var firstErr error + + if err := callAfterScanHook(ctx, m.strct.Addr()); err != nil && firstErr == nil { + firstErr = err + } + + for _, j := range m.joins { + switch j.Rel.Type { + case HasOneRelation, BelongsToRelation: + if err := j.JoinModel.AfterScan(ctx); err != nil && firstErr == nil { + firstErr = err + } + } + } + + return firstErr } -func (m *structTableModel) AfterSelect(db DB) error { - if !m.table.HasFlag(AfterSelectHookFlag) { - return nil +func (m *structTableModel) AfterSelect(ctx context.Context) error { + if m.table.hasFlag(afterSelectHookFlag) { + return callAfterSelectHook(ctx, m.strct.Addr()) } - return callAfterSelectHook(m.strct.Addr(), db) + return nil } -func (m *structTableModel) BeforeInsert(db DB) error { - if !m.table.HasFlag(BeforeInsertHookFlag) { - return nil +func (m *structTableModel) BeforeInsert(ctx context.Context) (context.Context, error) { + if m.table.hasFlag(beforeInsertHookFlag) { + return callBeforeInsertHook(ctx, m.strct.Addr()) } - return callBeforeInsertHook(m.strct.Addr(), db) + return ctx, nil } -func (m *structTableModel) AfterInsert(db DB) error { - if !m.table.HasFlag(AfterInsertHookFlag) { - return nil +func (m *structTableModel) AfterInsert(ctx context.Context) error { + if m.table.hasFlag(afterInsertHookFlag) { + return callAfterInsertHook(ctx, m.strct.Addr()) } - return callAfterInsertHook(m.strct.Addr(), db) + return nil } -func (m *structTableModel) BeforeUpdate(db DB) error { - if !m.table.HasFlag(BeforeUpdateHookFlag) { - return nil +func (m *structTableModel) BeforeUpdate(ctx context.Context) (context.Context, error) { + if m.table.hasFlag(beforeUpdateHookFlag) && !m.IsNil() { + return callBeforeUpdateHook(ctx, m.strct.Addr()) } - return callBeforeUpdateHook(m.strct.Addr(), db) + return ctx, nil } -func (m *structTableModel) AfterUpdate(db DB) error { - if !m.table.HasFlag(AfterUpdateHookFlag) { - return nil +func (m *structTableModel) AfterUpdate(ctx context.Context) error { + if m.table.hasFlag(afterUpdateHookFlag) && !m.IsNil() { + return callAfterUpdateHook(ctx, m.strct.Addr()) } - return callAfterUpdateHook(m.strct.Addr(), db) + return nil } -func (m *structTableModel) BeforeDelete(db DB) error { - if !m.table.HasFlag(BeforeDeleteHookFlag) { - return nil +func (m *structTableModel) BeforeDelete(ctx context.Context) (context.Context, error) { + if m.table.hasFlag(beforeDeleteHookFlag) && !m.IsNil() { + return callBeforeDeleteHook(ctx, m.strct.Addr()) } - return callBeforeDeleteHook(m.strct.Addr(), db) + return ctx, nil } -func (m *structTableModel) AfterDelete(db DB) error { - if !m.table.HasFlag(AfterDeleteHookFlag) { - return nil +func (m *structTableModel) AfterDelete(ctx context.Context) error { + if m.table.hasFlag(afterDeleteHookFlag) && !m.IsNil() { + return callAfterDeleteHook(ctx, m.strct.Addr()) } - return callAfterDeleteHook(m.strct.Addr(), db) + return nil } -func (m *structTableModel) ScanColumn(colIdx int, colName string, b []byte) error { - ok, err := m.scanColumn(colIdx, colName, b) +func (m *structTableModel) ScanColumn( + col types.ColumnInfo, rd types.Reader, n int, +) error { + ok, err := m.scanColumn(col, rd, n) if ok { return err } - if m.table.HasFlag(discardUnknownColumns) { + if m.table.hasFlag(discardUnknownColumnsFlag) || col.Name[0] == '_' { return nil } - return fmt.Errorf("pg: can't find column=%s in %s (try discard_unknown_columns)", - colName, m.table) + return fmt.Errorf( + "pg: can't find column=%s in %s "+ + "(prefix the column with underscore or use discard_unknown_columns)", + col.Name, m.table, + ) } -func (m *structTableModel) scanColumn( - colIdx int, colName string, b []byte, -) (bool, error) { - // Don't init nil struct when value is NULL. - if b == nil && +func (m *structTableModel) scanColumn(col types.ColumnInfo, rd types.Reader, n int) (bool, error) { + // Don't init nil struct if value is NULL. + if n == -1 && !m.structInited && m.strct.Kind() == reflect.Ptr && m.strct.IsNil() { return true, nil } - err := m.initStruct() - if err != nil { + if err := m.initStruct(); err != nil { return true, err } - joinName, fieldName := splitColumn(colName) + joinName, fieldName := splitColumn(col.Name) if joinName != "" { if join := m.GetJoin(joinName); join != nil { - return join.JoinModel.scanColumn(colIdx, fieldName, b) + joinCol := col + joinCol.Name = fieldName + return join.JoinModel.scanColumn(joinCol, rd, n) } if m.table.ModelName == joinName { - return m.scanColumn(colIdx, fieldName, b) + joinCol := col + joinCol.Name = fieldName + return m.scanColumn(joinCol, rd, n) } } - field, ok := m.table.FieldsMap[colName] + field, ok := m.table.FieldsMap[col.Name] if !ok { return false, nil } - return true, field.ScanValue(m.strct, b) + return true, field.ScanValue(m.strct, rd, n) } func (m *structTableModel) GetJoin(name string) *join { @@ -299,6 +340,7 @@ func (m *structTableModel) join( hasColumnName = true break } + currJoin.Rel = rel index = append(index, rel.Field.Index...) @@ -308,7 +350,7 @@ func (m *structTableModel) join( lastJoin = j } else { - model, err := newTableModelIndex(bind, index, rel) + model, err := newTableModelIndex(m.table.Type, bind, index, rel) if err != nil { return nil } @@ -343,15 +385,9 @@ func (m *structTableModel) join( return lastJoin } -func (m *structTableModel) setDeletedAt() { - field := m.table.FieldsMap["deleted_at"] - value := field.Value(m.strct) - if value.Kind() == reflect.Ptr { - now := time.Now() - value.Set(reflect.ValueOf(&now)) - } else { - value.Set(reflect.ValueOf(time.Now())) - } +func (m *structTableModel) setSoftDeleteField() error { + fv := m.table.SoftDeleteField.Value(m.strct) + return m.table.SetSoftDeleteField(fv) } func splitColumn(s string) (string, string) { diff --git a/vendor/github.com/go-pg/pg/v10/orm/msgpack.go b/vendor/github.com/go-pg/pg/v10/orm/msgpack.go new file mode 100644 index 000000000..56c88a23e --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/msgpack.go @@ -0,0 +1,52 @@ +package orm + +import ( + "reflect" + + "github.com/vmihailenco/msgpack/v5" + + "github.com/go-pg/pg/v10/types" +) + +func msgpackAppender(_ reflect.Type) types.AppenderFunc { + return func(b []byte, v reflect.Value, flags int) []byte { + hexEnc := types.NewHexEncoder(b, flags) + + enc := msgpack.GetEncoder() + defer msgpack.PutEncoder(enc) + + enc.Reset(hexEnc) + if err := enc.EncodeValue(v); err != nil { + return types.AppendError(b, err) + } + + if err := hexEnc.Close(); err != nil { + return types.AppendError(b, err) + } + + return hexEnc.Bytes() + } +} + +func msgpackScanner(_ reflect.Type) types.ScannerFunc { + return func(v reflect.Value, rd types.Reader, n int) error { + if n <= 0 { + return nil + } + + hexDec, err := types.NewHexDecoder(rd, n) + if err != nil { + return err + } + + dec := msgpack.GetDecoder() + defer msgpack.PutDecoder(dec) + + dec.Reset(hexDec) + if err := dec.DecodeValue(v); err != nil { + return err + } + + return nil + } +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/orm.go b/vendor/github.com/go-pg/pg/v10/orm/orm.go new file mode 100644 index 000000000..d18993d2d --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/orm.go @@ -0,0 +1,58 @@ +/* +The API in this package is not stable and may change without any notice. +*/ +package orm + +import ( + "context" + "io" + + "github.com/go-pg/pg/v10/types" +) + +// ColumnScanner is used to scan column values. +type ColumnScanner interface { + // Scan assigns a column value from a row. + // + // An error should be returned if the value can not be stored + // without loss of information. + ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error +} + +type QueryAppender interface { + AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) +} + +type TemplateAppender interface { + AppendTemplate(b []byte) ([]byte, error) +} + +type QueryCommand interface { + QueryAppender + TemplateAppender + String() string + Operation() QueryOp + Clone() QueryCommand + Query() *Query +} + +// DB is a common interface for pg.DB and pg.Tx types. +type DB interface { + Model(model ...interface{}) *Query + ModelContext(c context.Context, model ...interface{}) *Query + + Exec(query interface{}, params ...interface{}) (Result, error) + ExecContext(c context.Context, query interface{}, params ...interface{}) (Result, error) + ExecOne(query interface{}, params ...interface{}) (Result, error) + ExecOneContext(c context.Context, query interface{}, params ...interface{}) (Result, error) + Query(model, query interface{}, params ...interface{}) (Result, error) + QueryContext(c context.Context, model, query interface{}, params ...interface{}) (Result, error) + QueryOne(model, query interface{}, params ...interface{}) (Result, error) + QueryOneContext(c context.Context, model, query interface{}, params ...interface{}) (Result, error) + + CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error) + CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error) + + Context() context.Context + Formatter() QueryFormatter +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/query.go b/vendor/github.com/go-pg/pg/v10/orm/query.go new file mode 100644 index 000000000..37ae194d6 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/query.go @@ -0,0 +1,1685 @@ +package orm + +import ( + "context" + "errors" + "fmt" + "io" + "reflect" + "strconv" + "strings" + "sync" + "time" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/types" +) + +type QueryOp string + +const ( + SelectOp QueryOp = "SELECT" + InsertOp QueryOp = "INSERT" + UpdateOp QueryOp = "UPDATE" + DeleteOp QueryOp = "DELETE" + CreateTableOp QueryOp = "CREATE TABLE" + DropTableOp QueryOp = "DROP TABLE" + CreateCompositeOp QueryOp = "CREATE COMPOSITE" + DropCompositeOp QueryOp = "DROP COMPOSITE" +) + +type queryFlag uint8 + +const ( + implicitModelFlag queryFlag = 1 << iota + deletedFlag + allWithDeletedFlag +) + +type withQuery struct { + name string + query QueryAppender +} + +type columnValue struct { + column string + value *SafeQueryAppender +} + +type union struct { + expr string + query *Query +} + +type Query struct { + ctx context.Context + db DB + stickyErr error + + model Model + tableModel TableModel + flags queryFlag + + with []withQuery + tables []QueryAppender + distinctOn []*SafeQueryAppender + columns []QueryAppender + set []QueryAppender + modelValues map[string]*SafeQueryAppender + extraValues []*columnValue + where []queryWithSepAppender + updWhere []queryWithSepAppender + group []QueryAppender + having []*SafeQueryAppender + union []*union + joins []QueryAppender + joinAppendOn func(app *condAppender) + order []QueryAppender + limit int + offset int + selFor *SafeQueryAppender + + onConflict *SafeQueryAppender + returning []*SafeQueryAppender +} + +func NewQuery(db DB, model ...interface{}) *Query { + ctx := context.Background() + if db != nil { + ctx = db.Context() + } + q := &Query{ctx: ctx} + return q.DB(db).Model(model...) +} + +func NewQueryContext(ctx context.Context, db DB, model ...interface{}) *Query { + return NewQuery(db, model...).Context(ctx) +} + +// New returns new zero Query bound to the current db. +func (q *Query) New() *Query { + clone := &Query{ + ctx: q.ctx, + db: q.db, + + model: q.model, + tableModel: cloneTableModelJoins(q.tableModel), + flags: q.flags, + } + return clone.withFlag(implicitModelFlag) +} + +// Clone clones the Query. +func (q *Query) Clone() *Query { + var modelValues map[string]*SafeQueryAppender + if len(q.modelValues) > 0 { + modelValues = make(map[string]*SafeQueryAppender, len(q.modelValues)) + for k, v := range q.modelValues { + modelValues[k] = v + } + } + + clone := &Query{ + ctx: q.ctx, + db: q.db, + stickyErr: q.stickyErr, + + model: q.model, + tableModel: cloneTableModelJoins(q.tableModel), + flags: q.flags, + + with: q.with[:len(q.with):len(q.with)], + tables: q.tables[:len(q.tables):len(q.tables)], + distinctOn: q.distinctOn[:len(q.distinctOn):len(q.distinctOn)], + columns: q.columns[:len(q.columns):len(q.columns)], + set: q.set[:len(q.set):len(q.set)], + modelValues: modelValues, + extraValues: q.extraValues[:len(q.extraValues):len(q.extraValues)], + where: q.where[:len(q.where):len(q.where)], + updWhere: q.updWhere[:len(q.updWhere):len(q.updWhere)], + joins: q.joins[:len(q.joins):len(q.joins)], + group: q.group[:len(q.group):len(q.group)], + having: q.having[:len(q.having):len(q.having)], + union: q.union[:len(q.union):len(q.union)], + order: q.order[:len(q.order):len(q.order)], + limit: q.limit, + offset: q.offset, + selFor: q.selFor, + + onConflict: q.onConflict, + returning: q.returning[:len(q.returning):len(q.returning)], + } + + return clone +} + +func cloneTableModelJoins(tm TableModel) TableModel { + switch tm := tm.(type) { + case *structTableModel: + if len(tm.joins) == 0 { + return tm + } + clone := *tm + clone.joins = clone.joins[:len(clone.joins):len(clone.joins)] + return &clone + case *sliceTableModel: + if len(tm.joins) == 0 { + return tm + } + clone := *tm + clone.joins = clone.joins[:len(clone.joins):len(clone.joins)] + return &clone + } + return tm +} + +func (q *Query) err(err error) *Query { + if q.stickyErr == nil { + q.stickyErr = err + } + return q +} + +func (q *Query) hasFlag(flag queryFlag) bool { + return hasFlag(q.flags, flag) +} + +func hasFlag(flags, flag queryFlag) bool { + return flags&flag != 0 +} + +func (q *Query) withFlag(flag queryFlag) *Query { + q.flags |= flag + return q +} + +func (q *Query) withoutFlag(flag queryFlag) *Query { + q.flags &= ^flag + return q +} + +func (q *Query) Context(c context.Context) *Query { + q.ctx = c + return q +} + +func (q *Query) DB(db DB) *Query { + q.db = db + return q +} + +func (q *Query) Model(model ...interface{}) *Query { + var err error + switch l := len(model); { + case l == 0: + q.model = nil + case l == 1: + q.model, err = NewModel(model[0]) + case l > 1: + q.model, err = NewModel(&model) + default: + panic("not reached") + } + if err != nil { + q = q.err(err) + } + + q.tableModel, _ = q.model.(TableModel) + + return q.withoutFlag(implicitModelFlag) +} + +func (q *Query) TableModel() TableModel { + return q.tableModel +} + +func (q *Query) isSoftDelete() bool { + if q.tableModel != nil { + return q.tableModel.Table().SoftDeleteField != nil && !q.hasFlag(allWithDeletedFlag) + } + return false +} + +// Deleted adds `WHERE deleted_at IS NOT NULL` clause for soft deleted models. +func (q *Query) Deleted() *Query { + if q.tableModel != nil { + if err := q.tableModel.Table().mustSoftDelete(); err != nil { + return q.err(err) + } + } + return q.withFlag(deletedFlag).withoutFlag(allWithDeletedFlag) +} + +// AllWithDeleted changes query to return all rows including soft deleted ones. +func (q *Query) AllWithDeleted() *Query { + if q.tableModel != nil { + if err := q.tableModel.Table().mustSoftDelete(); err != nil { + return q.err(err) + } + } + return q.withFlag(allWithDeletedFlag).withoutFlag(deletedFlag) +} + +// With adds subq as common table expression with the given name. +func (q *Query) With(name string, subq *Query) *Query { + return q._with(name, NewSelectQuery(subq)) +} + +func (q *Query) WithInsert(name string, subq *Query) *Query { + return q._with(name, NewInsertQuery(subq)) +} + +func (q *Query) WithUpdate(name string, subq *Query) *Query { + return q._with(name, NewUpdateQuery(subq, false)) +} + +func (q *Query) WithDelete(name string, subq *Query) *Query { + return q._with(name, NewDeleteQuery(subq)) +} + +func (q *Query) _with(name string, subq QueryAppender) *Query { + q.with = append(q.with, withQuery{ + name: name, + query: subq, + }) + return q +} + +// WrapWith creates new Query and adds to it current query as +// common table expression with the given name. +func (q *Query) WrapWith(name string) *Query { + wrapper := q.New() + wrapper.with = q.with + q.with = nil + wrapper = wrapper.With(name, q) + return wrapper +} + +func (q *Query) Table(tables ...string) *Query { + for _, table := range tables { + q.tables = append(q.tables, fieldAppender{table}) + } + return q +} + +func (q *Query) TableExpr(expr string, params ...interface{}) *Query { + q.tables = append(q.tables, SafeQuery(expr, params...)) + return q +} + +func (q *Query) Distinct() *Query { + q.distinctOn = make([]*SafeQueryAppender, 0) + return q +} + +func (q *Query) DistinctOn(expr string, params ...interface{}) *Query { + q.distinctOn = append(q.distinctOn, SafeQuery(expr, params...)) + return q +} + +// Column adds a column to the Query quoting it according to PostgreSQL rules. +// Does not expand params like ?TableAlias etc. +// ColumnExpr can be used to bypass quoting restriction or for params expansion. +// Column name can be: +// - column_name, +// - table_alias.column_name, +// - table_alias.*. +func (q *Query) Column(columns ...string) *Query { + for _, column := range columns { + if column == "_" { + if q.columns == nil { + q.columns = make([]QueryAppender, 0) + } + continue + } + + q.columns = append(q.columns, fieldAppender{column}) + } + return q +} + +// ColumnExpr adds column expression to the Query. +func (q *Query) ColumnExpr(expr string, params ...interface{}) *Query { + q.columns = append(q.columns, SafeQuery(expr, params...)) + return q +} + +// ExcludeColumn excludes a column from the list of to be selected columns. +func (q *Query) ExcludeColumn(columns ...string) *Query { + if q.columns == nil { + for _, f := range q.tableModel.Table().Fields { + q.columns = append(q.columns, fieldAppender{f.SQLName}) + } + } + + for _, col := range columns { + if !q.excludeColumn(col) { + return q.err(fmt.Errorf("pg: can't find column=%q", col)) + } + } + return q +} + +func (q *Query) excludeColumn(column string) bool { + for i := 0; i < len(q.columns); i++ { + app, ok := q.columns[i].(fieldAppender) + if ok && app.field == column { + q.columns = append(q.columns[:i], q.columns[i+1:]...) + return true + } + } + return false +} + +func (q *Query) getFields() ([]*Field, error) { + return q._getFields(false) +} + +func (q *Query) getDataFields() ([]*Field, error) { + return q._getFields(true) +} + +func (q *Query) _getFields(omitPKs bool) ([]*Field, error) { + table := q.tableModel.Table() + columns := make([]*Field, 0, len(q.columns)) + for _, col := range q.columns { + f, ok := col.(fieldAppender) + if !ok { + continue + } + + field, err := table.GetField(f.field) + if err != nil { + return nil, err + } + + if omitPKs && field.hasFlag(PrimaryKeyFlag) { + continue + } + + columns = append(columns, field) + } + return columns, nil +} + +// Relation adds a relation to the query. Relation name can be: +// - RelationName to select all columns, +// - RelationName.column_name, +// - RelationName._ to join relation without selecting relation columns. +func (q *Query) Relation(name string, apply ...func(*Query) (*Query, error)) *Query { + var fn func(*Query) (*Query, error) + if len(apply) == 1 { + fn = apply[0] + } else if len(apply) > 1 { + panic("only one apply function is supported") + } + + join := q.tableModel.Join(name, fn) + if join == nil { + return q.err(fmt.Errorf("%s does not have relation=%q", + q.tableModel.Table(), name)) + } + + if fn == nil { + return q + } + + switch join.Rel.Type { + case HasOneRelation, BelongsToRelation: + q.joinAppendOn = join.AppendOn + return q.Apply(fn) + default: + q.joinAppendOn = nil + return q + } +} + +func (q *Query) Set(set string, params ...interface{}) *Query { + q.set = append(q.set, SafeQuery(set, params...)) + return q +} + +// Value overwrites model value for the column in INSERT and UPDATE queries. +func (q *Query) Value(column string, value string, params ...interface{}) *Query { + if !q.hasTableModel() { + q.err(errModelNil) + return q + } + + table := q.tableModel.Table() + if _, ok := table.FieldsMap[column]; ok { + if q.modelValues == nil { + q.modelValues = make(map[string]*SafeQueryAppender) + } + q.modelValues[column] = SafeQuery(value, params...) + } else { + q.extraValues = append(q.extraValues, &columnValue{ + column: column, + value: SafeQuery(value, params...), + }) + } + + return q +} + +func (q *Query) Where(condition string, params ...interface{}) *Query { + q.addWhere(&condAppender{ + sep: " AND ", + cond: condition, + params: params, + }) + return q +} + +func (q *Query) WhereOr(condition string, params ...interface{}) *Query { + q.addWhere(&condAppender{ + sep: " OR ", + cond: condition, + params: params, + }) + return q +} + +// WhereGroup encloses conditions added in the function in parentheses. +// +// q.Where("TRUE"). +// WhereGroup(func(q *pg.Query) (*pg.Query, error) { +// q = q.WhereOr("FALSE").WhereOr("TRUE"). +// return q, nil +// }) +// +// generates +// +// WHERE TRUE AND (FALSE OR TRUE) +func (q *Query) WhereGroup(fn func(*Query) (*Query, error)) *Query { + return q.whereGroup(" AND ", fn) +} + +// WhereGroup encloses conditions added in the function in parentheses. +// +// q.Where("TRUE"). +// WhereNotGroup(func(q *pg.Query) (*pg.Query, error) { +// q = q.WhereOr("FALSE").WhereOr("TRUE"). +// return q, nil +// }) +// +// generates +// +// WHERE TRUE AND NOT (FALSE OR TRUE) +func (q *Query) WhereNotGroup(fn func(*Query) (*Query, error)) *Query { + return q.whereGroup(" AND NOT ", fn) +} + +// WhereOrGroup encloses conditions added in the function in parentheses. +// +// q.Where("TRUE"). +// WhereOrGroup(func(q *pg.Query) (*pg.Query, error) { +// q = q.Where("FALSE").Where("TRUE"). +// return q, nil +// }) +// +// generates +// +// WHERE TRUE OR (FALSE AND TRUE) +func (q *Query) WhereOrGroup(fn func(*Query) (*Query, error)) *Query { + return q.whereGroup(" OR ", fn) +} + +// WhereOrGroup encloses conditions added in the function in parentheses. +// +// q.Where("TRUE"). +// WhereOrGroup(func(q *pg.Query) (*pg.Query, error) { +// q = q.Where("FALSE").Where("TRUE"). +// return q, nil +// }) +// +// generates +// +// WHERE TRUE OR NOT (FALSE AND TRUE) +func (q *Query) WhereOrNotGroup(fn func(*Query) (*Query, error)) *Query { + return q.whereGroup(" OR NOT ", fn) +} + +func (q *Query) whereGroup(conj string, fn func(*Query) (*Query, error)) *Query { + saved := q.where + q.where = nil + + newq, err := fn(q) + if err != nil { + q.err(err) + return q + } + + if len(newq.where) == 0 { + newq.where = saved + return newq + } + + f := &condGroupAppender{ + sep: conj, + cond: newq.where, + } + newq.where = saved + newq.addWhere(f) + + return newq +} + +// WhereIn is a shortcut for Where and pg.In. +func (q *Query) WhereIn(where string, slice interface{}) *Query { + return q.Where(where, types.In(slice)) +} + +// WhereInOr is a shortcut for WhereOr and pg.In. +func (q *Query) WhereInOr(where string, slice interface{}) *Query { + return q.WhereOr(where, types.In(slice)) +} + +// WhereInMulti is a shortcut for Where and pg.InMulti. +func (q *Query) WhereInMulti(where string, values ...interface{}) *Query { + return q.Where(where, types.InMulti(values...)) +} + +func (q *Query) addWhere(f queryWithSepAppender) { + if q.onConflictDoUpdate() { + q.updWhere = append(q.updWhere, f) + } else { + q.where = append(q.where, f) + } +} + +// WherePK adds condition based on the model primary keys. +// Usually it is the same as: +// +// Where("id = ?id") +func (q *Query) WherePK() *Query { + if !q.hasTableModel() { + q.err(errModelNil) + return q + } + + if err := q.tableModel.Table().checkPKs(); err != nil { + q.err(err) + return q + } + + switch q.tableModel.Kind() { + case reflect.Struct: + q.where = append(q.where, wherePKStructQuery{q}) + return q + case reflect.Slice: + q.joins = append(q.joins, joinPKSliceQuery{q: q}) + q.where = append(q.where, wherePKSliceQuery{q: q}) + q = q.OrderExpr(`"_data"."ordering" ASC`) + return q + } + + panic("not reached") +} + +func (q *Query) Join(join string, params ...interface{}) *Query { + j := &joinQuery{ + join: SafeQuery(join, params...), + } + q.joins = append(q.joins, j) + q.joinAppendOn = j.AppendOn + return q +} + +// JoinOn appends join condition to the last join. +func (q *Query) JoinOn(condition string, params ...interface{}) *Query { + if q.joinAppendOn == nil { + q.err(errors.New("pg: no joins to apply JoinOn")) + return q + } + q.joinAppendOn(&condAppender{ + sep: " AND ", + cond: condition, + params: params, + }) + return q +} + +func (q *Query) JoinOnOr(condition string, params ...interface{}) *Query { + if q.joinAppendOn == nil { + q.err(errors.New("pg: no joins to apply JoinOn")) + return q + } + q.joinAppendOn(&condAppender{ + sep: " OR ", + cond: condition, + params: params, + }) + return q +} + +func (q *Query) Group(columns ...string) *Query { + for _, column := range columns { + q.group = append(q.group, fieldAppender{column}) + } + return q +} + +func (q *Query) GroupExpr(group string, params ...interface{}) *Query { + q.group = append(q.group, SafeQuery(group, params...)) + return q +} + +func (q *Query) Having(having string, params ...interface{}) *Query { + q.having = append(q.having, SafeQuery(having, params...)) + return q +} + +func (q *Query) Union(other *Query) *Query { + return q.addUnion(" UNION ", other) +} + +func (q *Query) UnionAll(other *Query) *Query { + return q.addUnion(" UNION ALL ", other) +} + +func (q *Query) Intersect(other *Query) *Query { + return q.addUnion(" INTERSECT ", other) +} + +func (q *Query) IntersectAll(other *Query) *Query { + return q.addUnion(" INTERSECT ALL ", other) +} + +func (q *Query) Except(other *Query) *Query { + return q.addUnion(" EXCEPT ", other) +} + +func (q *Query) ExceptAll(other *Query) *Query { + return q.addUnion(" EXCEPT ALL ", other) +} + +func (q *Query) addUnion(expr string, other *Query) *Query { + q.union = append(q.union, &union{ + expr: expr, + query: other, + }) + return q +} + +// Order adds sort order to the Query quoting column name. Does not expand params like ?TableAlias etc. +// OrderExpr can be used to bypass quoting restriction or for params expansion. +func (q *Query) Order(orders ...string) *Query { +loop: + for _, order := range orders { + if order == "" { + continue + } + ind := strings.Index(order, " ") + if ind != -1 { + field := order[:ind] + sort := order[ind+1:] + switch internal.UpperString(sort) { + case "ASC", "DESC", "ASC NULLS FIRST", "DESC NULLS FIRST", + "ASC NULLS LAST", "DESC NULLS LAST": + q = q.OrderExpr("? ?", types.Ident(field), types.Safe(sort)) + continue loop + } + } + + q.order = append(q.order, fieldAppender{order}) + } + return q +} + +// Order adds sort order to the Query. +func (q *Query) OrderExpr(order string, params ...interface{}) *Query { + if order != "" { + q.order = append(q.order, SafeQuery(order, params...)) + } + return q +} + +func (q *Query) Limit(n int) *Query { + q.limit = n + return q +} + +func (q *Query) Offset(n int) *Query { + q.offset = n + return q +} + +func (q *Query) OnConflict(s string, params ...interface{}) *Query { + q.onConflict = SafeQuery(s, params...) + return q +} + +func (q *Query) onConflictDoUpdate() bool { + return q.onConflict != nil && + strings.HasSuffix(internal.UpperString(q.onConflict.query), "DO UPDATE") +} + +// Returning adds a RETURNING clause to the query. +// +// `Returning("NULL")` can be used to suppress default returning clause +// generated by go-pg for INSERT queries to get values for null columns. +func (q *Query) Returning(s string, params ...interface{}) *Query { + q.returning = append(q.returning, SafeQuery(s, params...)) + return q +} + +func (q *Query) For(s string, params ...interface{}) *Query { + q.selFor = SafeQuery(s, params...) + return q +} + +// Apply calls the fn passing the Query as an argument. +func (q *Query) Apply(fn func(*Query) (*Query, error)) *Query { + qq, err := fn(q) + if err != nil { + q.err(err) + return q + } + return qq +} + +// Count returns number of rows matching the query using count aggregate function. +func (q *Query) Count() (int, error) { + if q.stickyErr != nil { + return 0, q.stickyErr + } + + var count int + _, err := q.db.QueryOneContext( + q.ctx, Scan(&count), q.countSelectQuery("count(*)"), q.tableModel) + return count, err +} + +func (q *Query) countSelectQuery(column string) *SelectQuery { + return &SelectQuery{ + q: q, + count: column, + } +} + +// First sorts rows by primary key and selects the first row. +// It is a shortcut for: +// +// q.OrderExpr("id ASC").Limit(1) +func (q *Query) First() error { + table := q.tableModel.Table() + + if err := table.checkPKs(); err != nil { + return err + } + + b := appendColumns(nil, table.Alias, table.PKs) + return q.OrderExpr(internal.BytesToString(b)).Limit(1).Select() +} + +// Last sorts rows by primary key and selects the last row. +// It is a shortcut for: +// +// q.OrderExpr("id DESC").Limit(1) +func (q *Query) Last() error { + table := q.tableModel.Table() + + if err := table.checkPKs(); err != nil { + return err + } + + // TODO: fix for multi columns + b := appendColumns(nil, table.Alias, table.PKs) + b = append(b, " DESC"...) + return q.OrderExpr(internal.BytesToString(b)).Limit(1).Select() +} + +// Select selects the model. +func (q *Query) Select(values ...interface{}) error { + if q.stickyErr != nil { + return q.stickyErr + } + + model, err := q.newModel(values) + if err != nil { + return err + } + + res, err := q.query(q.ctx, model, NewSelectQuery(q)) + if err != nil { + return err + } + + if res.RowsReturned() > 0 { + if q.tableModel != nil { + if err := q.selectJoins(q.tableModel.GetJoins()); err != nil { + return err + } + } + } + + if err := model.AfterSelect(q.ctx); err != nil { + return err + } + + return nil +} + +func (q *Query) newModel(values []interface{}) (Model, error) { + if len(values) > 0 { + return newScanModel(values) + } + return q.tableModel, nil +} + +func (q *Query) query(ctx context.Context, model Model, query interface{}) (Result, error) { + if _, ok := model.(useQueryOne); ok { + return q.db.QueryOneContext(ctx, model, query, q.tableModel) + } + return q.db.QueryContext(ctx, model, query, q.tableModel) +} + +// SelectAndCount runs Select and Count in two goroutines, +// waits for them to finish and returns the result. If query limit is -1 +// it does not select any data and only counts the results. +func (q *Query) SelectAndCount(values ...interface{}) (count int, firstErr error) { + if q.stickyErr != nil { + return 0, q.stickyErr + } + + var wg sync.WaitGroup + var mu sync.Mutex + + if q.limit >= 0 { + wg.Add(1) + go func() { + defer wg.Done() + err := q.Select(values...) + if err != nil { + mu.Lock() + if firstErr == nil { + firstErr = err + } + mu.Unlock() + } + }() + } + + wg.Add(1) + go func() { + defer wg.Done() + var err error + count, err = q.Count() + if err != nil { + mu.Lock() + if firstErr == nil { + firstErr = err + } + mu.Unlock() + } + }() + + wg.Wait() + return count, firstErr +} + +// SelectAndCountEstimate runs Select and CountEstimate in two goroutines, +// waits for them to finish and returns the result. If query limit is -1 +// it does not select any data and only counts the results. +func (q *Query) SelectAndCountEstimate(threshold int, values ...interface{}) (count int, firstErr error) { + if q.stickyErr != nil { + return 0, q.stickyErr + } + + var wg sync.WaitGroup + var mu sync.Mutex + + if q.limit >= 0 { + wg.Add(1) + go func() { + defer wg.Done() + err := q.Select(values...) + if err != nil { + mu.Lock() + if firstErr == nil { + firstErr = err + } + mu.Unlock() + } + }() + } + + wg.Add(1) + go func() { + defer wg.Done() + var err error + count, err = q.CountEstimate(threshold) + if err != nil { + mu.Lock() + if firstErr == nil { + firstErr = err + } + mu.Unlock() + } + }() + + wg.Wait() + return count, firstErr +} + +// ForEach calls the function for each row returned by the query +// without loading all rows into the memory. +// +// Function can accept a struct, a pointer to a struct, an orm.Model, +// or values for the columns in a row. Function must return an error. +func (q *Query) ForEach(fn interface{}) error { + m := newFuncModel(fn) + return q.Select(m) +} + +func (q *Query) forEachHasOneJoin(fn func(*join) error) error { + if q.tableModel == nil { + return nil + } + return q._forEachHasOneJoin(fn, q.tableModel.GetJoins()) +} + +func (q *Query) _forEachHasOneJoin(fn func(*join) error, joins []join) error { + for i := range joins { + j := &joins[i] + switch j.Rel.Type { + case HasOneRelation, BelongsToRelation: + err := fn(j) + if err != nil { + return err + } + + err = q._forEachHasOneJoin(fn, j.JoinModel.GetJoins()) + if err != nil { + return err + } + } + } + return nil +} + +func (q *Query) selectJoins(joins []join) error { + var err error + for i := range joins { + j := &joins[i] + if j.Rel.Type == HasOneRelation || j.Rel.Type == BelongsToRelation { + err = q.selectJoins(j.JoinModel.GetJoins()) + } else { + err = j.Select(q.db.Formatter(), q.New()) + } + if err != nil { + return err + } + } + return nil +} + +// Insert inserts the model. +func (q *Query) Insert(values ...interface{}) (Result, error) { + if q.stickyErr != nil { + return nil, q.stickyErr + } + + model, err := q.newModel(values) + if err != nil { + return nil, err + } + + ctx := q.ctx + + if q.tableModel != nil && q.tableModel.Table().hasFlag(beforeInsertHookFlag) { + ctx, err = q.tableModel.BeforeInsert(ctx) + if err != nil { + return nil, err + } + } + + query := NewInsertQuery(q) + res, err := q.returningQuery(ctx, model, query) + if err != nil { + return nil, err + } + + if q.tableModel != nil { + if err := q.tableModel.AfterInsert(ctx); err != nil { + return nil, err + } + } + + return res, nil +} + +// SelectOrInsert selects the model inserting one if it does not exist. +// It returns true when model was inserted. +func (q *Query) SelectOrInsert(values ...interface{}) (inserted bool, _ error) { + if q.stickyErr != nil { + return false, q.stickyErr + } + + var insertq *Query + var insertErr error + for i := 0; i < 5; i++ { + if i >= 2 { + dur := internal.RetryBackoff(i-2, 250*time.Millisecond, 5*time.Second) + if err := internal.Sleep(q.ctx, dur); err != nil { + return false, err + } + } + + err := q.Select(values...) + if err == nil { + return false, nil + } + if err != internal.ErrNoRows { + return false, err + } + + if insertq == nil { + insertq = q + if len(insertq.columns) > 0 { + insertq = insertq.Clone() + insertq.columns = nil + } + } + + res, err := insertq.Insert(values...) + if err != nil { + insertErr = err + if err == internal.ErrNoRows { + continue + } + if pgErr, ok := err.(internal.PGError); ok { + if pgErr.IntegrityViolation() { + continue + } + if pgErr.Field('C') == "55000" { + // Retry on "#55000 attempted to delete invisible tuple". + continue + } + } + return false, err + } + if res.RowsAffected() == 1 { + return true, nil + } + } + + err := fmt.Errorf( + "pg: SelectOrInsert: select returns no rows (insert fails with err=%q)", + insertErr) + return false, err +} + +// Update updates the model. +func (q *Query) Update(scan ...interface{}) (Result, error) { + return q.update(scan, false) +} + +// Update updates the model omitting fields with zero values such as: +// - empty string, +// - 0, +// - zero time, +// - empty map or slice, +// - byte array with all zeroes, +// - nil ptr, +// - types with method `IsZero() == true`. +func (q *Query) UpdateNotZero(scan ...interface{}) (Result, error) { + return q.update(scan, true) +} + +func (q *Query) update(values []interface{}, omitZero bool) (Result, error) { + if q.stickyErr != nil { + return nil, q.stickyErr + } + + model, err := q.newModel(values) + if err != nil { + return nil, err + } + + c := q.ctx + + if q.tableModel != nil { + c, err = q.tableModel.BeforeUpdate(c) + if err != nil { + return nil, err + } + } + + query := NewUpdateQuery(q, omitZero) + res, err := q.returningQuery(c, model, query) + if err != nil { + return nil, err + } + + if q.tableModel != nil { + err = q.tableModel.AfterUpdate(c) + if err != nil { + return nil, err + } + } + + return res, nil +} + +func (q *Query) returningQuery(c context.Context, model Model, query interface{}) (Result, error) { + if !q.hasReturning() { + return q.db.QueryContext(c, model, query, q.tableModel) + } + if _, ok := model.(useQueryOne); ok { + return q.db.QueryOneContext(c, model, query, q.tableModel) + } + return q.db.QueryContext(c, model, query, q.tableModel) +} + +// Delete deletes the model. When model has deleted_at column the row +// is soft deleted instead. +func (q *Query) Delete(values ...interface{}) (Result, error) { + if q.tableModel == nil { + return q.ForceDelete(values...) + } + + table := q.tableModel.Table() + if table.SoftDeleteField == nil { + return q.ForceDelete(values...) + } + + clone := q.Clone() + if q.tableModel.IsNil() { + if table.SoftDeleteField.SQLType == pgTypeBigint { + clone = clone.Set("? = ?", table.SoftDeleteField.Column, time.Now().UnixNano()) + } else { + clone = clone.Set("? = ?", table.SoftDeleteField.Column, time.Now()) + } + } else { + if err := clone.tableModel.setSoftDeleteField(); err != nil { + return nil, err + } + clone = clone.Column(table.SoftDeleteField.SQLName) + } + return clone.Update(values...) +} + +// Delete forces delete of the model with deleted_at column. +func (q *Query) ForceDelete(values ...interface{}) (Result, error) { + if q.stickyErr != nil { + return nil, q.stickyErr + } + if q.tableModel == nil { + return nil, errModelNil + } + q = q.withFlag(deletedFlag) + + model, err := q.newModel(values) + if err != nil { + return nil, err + } + + ctx := q.ctx + + if q.tableModel != nil { + ctx, err = q.tableModel.BeforeDelete(ctx) + if err != nil { + return nil, err + } + } + + res, err := q.returningQuery(ctx, model, NewDeleteQuery(q)) + if err != nil { + return nil, err + } + + if q.tableModel != nil { + if err := q.tableModel.AfterDelete(ctx); err != nil { + return nil, err + } + } + + return res, nil +} + +func (q *Query) CreateTable(opt *CreateTableOptions) error { + _, err := q.db.ExecContext(q.ctx, NewCreateTableQuery(q, opt)) + return err +} + +func (q *Query) DropTable(opt *DropTableOptions) error { + _, err := q.db.ExecContext(q.ctx, NewDropTableQuery(q, opt)) + return err +} + +func (q *Query) CreateComposite(opt *CreateCompositeOptions) error { + _, err := q.db.ExecContext(q.ctx, NewCreateCompositeQuery(q, opt)) + return err +} + +func (q *Query) DropComposite(opt *DropCompositeOptions) error { + _, err := q.db.ExecContext(q.ctx, NewDropCompositeQuery(q, opt)) + return err +} + +// Exec is an alias for DB.Exec. +func (q *Query) Exec(query interface{}, params ...interface{}) (Result, error) { + params = append(params, q.tableModel) + return q.db.ExecContext(q.ctx, query, params...) +} + +// ExecOne is an alias for DB.ExecOne. +func (q *Query) ExecOne(query interface{}, params ...interface{}) (Result, error) { + params = append(params, q.tableModel) + return q.db.ExecOneContext(q.ctx, query, params...) +} + +// Query is an alias for DB.Query. +func (q *Query) Query(model, query interface{}, params ...interface{}) (Result, error) { + params = append(params, q.tableModel) + return q.db.QueryContext(q.ctx, model, query, params...) +} + +// QueryOne is an alias for DB.QueryOne. +func (q *Query) QueryOne(model, query interface{}, params ...interface{}) (Result, error) { + params = append(params, q.tableModel) + return q.db.QueryOneContext(q.ctx, model, query, params...) +} + +// CopyFrom is an alias from DB.CopyFrom. +func (q *Query) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error) { + params = append(params, q.tableModel) + return q.db.CopyFrom(r, query, params...) +} + +// CopyTo is an alias from DB.CopyTo. +func (q *Query) CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error) { + params = append(params, q.tableModel) + return q.db.CopyTo(w, query, params...) +} + +var _ QueryAppender = (*Query)(nil) + +func (q *Query) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + return NewSelectQuery(q).AppendQuery(fmter, b) +} + +// Exists returns true or false depending if there are any rows matching the query. +func (q *Query) Exists() (bool, error) { + q = q.Clone() // copy to not change original query + q.columns = []QueryAppender{SafeQuery("1")} + q.order = nil + q.limit = 1 + res, err := q.db.ExecContext(q.ctx, NewSelectQuery(q)) + if err != nil { + return false, err + } + return res.RowsAffected() > 0, nil +} + +func (q *Query) hasTableModel() bool { + return q.tableModel != nil && !q.tableModel.IsNil() +} + +func (q *Query) hasExplicitTableModel() bool { + return q.tableModel != nil && !q.hasFlag(implicitModelFlag) +} + +func (q *Query) modelHasTableName() bool { + return q.hasExplicitTableModel() && q.tableModel.Table().SQLName != "" +} + +func (q *Query) modelHasTableAlias() bool { + return q.hasExplicitTableModel() && q.tableModel.Table().Alias != "" +} + +func (q *Query) hasTables() bool { + return q.modelHasTableName() || len(q.tables) > 0 +} + +func (q *Query) appendFirstTable(fmter QueryFormatter, b []byte) ([]byte, error) { + if q.modelHasTableName() { + return fmter.FormatQuery(b, string(q.tableModel.Table().SQLName)), nil + } + if len(q.tables) > 0 { + return q.tables[0].AppendQuery(fmter, b) + } + return b, nil +} + +func (q *Query) appendFirstTableWithAlias(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.modelHasTableName() { + table := q.tableModel.Table() + b = fmter.FormatQuery(b, string(table.SQLName)) + if table.Alias != table.SQLName { + b = append(b, " AS "...) + b = append(b, table.Alias...) + } + return b, nil + } + + if len(q.tables) > 0 { + b, err = q.tables[0].AppendQuery(fmter, b) + if err != nil { + return nil, err + } + if q.modelHasTableAlias() { + table := q.tableModel.Table() + if table.Alias != table.SQLName { + b = append(b, " AS "...) + b = append(b, table.Alias...) + } + } + } + + return b, nil +} + +func (q *Query) hasMultiTables() bool { + if q.modelHasTableName() { + return len(q.tables) >= 1 + } + return len(q.tables) >= 2 +} + +func (q *Query) appendOtherTables(fmter QueryFormatter, b []byte) (_ []byte, err error) { + tables := q.tables + if !q.modelHasTableName() { + tables = tables[1:] + } + for i, f := range tables { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + return b, nil +} + +func (q *Query) appendColumns(fmter QueryFormatter, b []byte) (_ []byte, err error) { + for i, f := range q.columns { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + return b, nil +} + +func (q *Query) mustAppendWhere(fmter QueryFormatter, b []byte) ([]byte, error) { + if len(q.where) == 0 { + err := errors.New( + "pg: Update and Delete queries require Where clause (try WherePK)") + return nil, err + } + return q.appendWhere(fmter, b) +} + +func (q *Query) appendWhere(fmter QueryFormatter, b []byte) (_ []byte, err error) { + isSoftDelete := q.isSoftDelete() + + if len(q.where) > 0 { + if isSoftDelete { + b = append(b, '(') + } + + b, err = q._appendWhere(fmter, b, q.where) + if err != nil { + return nil, err + } + + if isSoftDelete { + b = append(b, ')') + } + } + + if isSoftDelete { + if len(q.where) > 0 { + b = append(b, " AND "...) + } + b = append(b, q.tableModel.Table().Alias...) + b = q.appendSoftDelete(b) + } + + return b, nil +} + +func (q *Query) appendSoftDelete(b []byte) []byte { + b = append(b, '.') + b = append(b, q.tableModel.Table().SoftDeleteField.Column...) + if q.hasFlag(deletedFlag) { + b = append(b, " IS NOT NULL"...) + } else { + b = append(b, " IS NULL"...) + } + return b +} + +func (q *Query) appendUpdWhere(fmter QueryFormatter, b []byte) ([]byte, error) { + return q._appendWhere(fmter, b, q.updWhere) +} + +func (q *Query) _appendWhere( + fmter QueryFormatter, b []byte, where []queryWithSepAppender, +) (_ []byte, err error) { + for i, f := range where { + start := len(b) + + if i > 0 { + b = f.AppendSep(b) + } + + before := len(b) + + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + + if len(b) == before { + b = b[:start] + } + } + return b, nil +} + +func (q *Query) appendSet(fmter QueryFormatter, b []byte) (_ []byte, err error) { + b = append(b, " SET "...) + for i, f := range q.set { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + return b, nil +} + +func (q *Query) hasReturning() bool { + if len(q.returning) == 0 { + return false + } + if len(q.returning) == 1 { + switch q.returning[0].query { + case "null", "NULL": + return false + } + } + return true +} + +func (q *Query) appendReturning(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if !q.hasReturning() { + return b, nil + } + + b = append(b, " RETURNING "...) + for i, f := range q.returning { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + return b, nil +} + +func (q *Query) appendWith(fmter QueryFormatter, b []byte) (_ []byte, err error) { + b = append(b, "WITH "...) + for i, with := range q.with { + if i > 0 { + b = append(b, ", "...) + } + b = types.AppendIdent(b, with.name, 1) + b = append(b, " AS ("...) + + b, err = with.query.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + + b = append(b, ')') + } + b = append(b, ' ') + return b, nil +} + +func (q *Query) isSliceModelWithData() bool { + if !q.hasTableModel() { + return false + } + m, ok := q.tableModel.(*sliceTableModel) + return ok && m.sliceLen > 0 +} + +//------------------------------------------------------------------------------ + +type wherePKStructQuery struct { + q *Query +} + +var _ queryWithSepAppender = (*wherePKStructQuery)(nil) + +func (wherePKStructQuery) AppendSep(b []byte) []byte { + return append(b, " AND "...) +} + +func (q wherePKStructQuery) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + table := q.q.tableModel.Table() + value := q.q.tableModel.Value() + return appendColumnAndValue(fmter, b, value, table.Alias, table.PKs), nil +} + +func appendColumnAndValue( + fmter QueryFormatter, b []byte, v reflect.Value, alias types.Safe, fields []*Field, +) []byte { + isPlaceholder := isTemplateFormatter(fmter) + for i, f := range fields { + if i > 0 { + b = append(b, " AND "...) + } + b = append(b, alias...) + b = append(b, '.') + b = append(b, f.Column...) + b = append(b, " = "...) + if isPlaceholder { + b = append(b, '?') + } else { + b = f.AppendValue(b, v, 1) + } + } + return b +} + +//------------------------------------------------------------------------------ + +type wherePKSliceQuery struct { + q *Query +} + +var _ queryWithSepAppender = (*wherePKSliceQuery)(nil) + +func (wherePKSliceQuery) AppendSep(b []byte) []byte { + return append(b, " AND "...) +} + +func (q wherePKSliceQuery) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + table := q.q.tableModel.Table() + + for i, f := range table.PKs { + if i > 0 { + b = append(b, " AND "...) + } + b = append(b, table.Alias...) + b = append(b, '.') + b = append(b, f.Column...) + b = append(b, " = "...) + b = append(b, `"_data".`...) + b = append(b, f.Column...) + } + + return b, nil +} + +type joinPKSliceQuery struct { + q *Query +} + +var _ QueryAppender = (*joinPKSliceQuery)(nil) + +func (q joinPKSliceQuery) AppendQuery(fmter QueryFormatter, b []byte) ([]byte, error) { + table := q.q.tableModel.Table() + slice := q.q.tableModel.Value() + + b = append(b, " JOIN (VALUES "...) + + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + if i > 0 { + b = append(b, ", "...) + } + + el := indirect(slice.Index(i)) + + b = append(b, '(') + for i, f := range table.PKs { + if i > 0 { + b = append(b, ", "...) + } + + b = f.AppendValue(b, el, 1) + + if f.UserSQLType != "" { + b = append(b, "::"...) + b = append(b, f.SQLType...) + } + } + + b = append(b, ", "...) + b = strconv.AppendInt(b, int64(i), 10) + + b = append(b, ')') + } + + b = append(b, `) AS "_data" (`...) + + for i, f := range table.PKs { + if i > 0 { + b = append(b, ", "...) + } + b = append(b, f.Column...) + } + + b = append(b, ", "...) + b = append(b, `"ordering"`...) + b = append(b, ") ON TRUE"...) + + return b, nil +} diff --git a/vendor/github.com/go-pg/pg/orm/relation.go b/vendor/github.com/go-pg/pg/v10/orm/relation.go similarity index 57% rename from vendor/github.com/go-pg/pg/orm/relation.go rename to vendor/github.com/go-pg/pg/v10/orm/relation.go index 720e6ad7e..28d915bcd 100644 --- a/vendor/github.com/go-pg/pg/orm/relation.go +++ b/vendor/github.com/go-pg/pg/v10/orm/relation.go @@ -3,11 +3,12 @@ package orm import ( "fmt" - "github.com/go-pg/pg/types" + "github.com/go-pg/pg/v10/types" ) const ( - HasOneRelation = 1 << iota + InvalidRelation = iota + HasOneRelation BelongsToRelation HasManyRelation Many2ManyRelation @@ -17,14 +18,14 @@ type Relation struct { Type int Field *Field JoinTable *Table - FKs []*Field + BaseFKs []*Field + JoinFKs []*Field Polymorphic *Field - FKValues []*Field - M2MTableName types.Q - M2MTableAlias types.Q - BaseFKs []string - JoinFKs []string + M2MTableName types.Safe + M2MTableAlias types.Safe + M2MBaseFKs []string + M2MJoinFKs []string } func (r *Relation) String() string { diff --git a/vendor/github.com/go-pg/pg/orm/result.go b/vendor/github.com/go-pg/pg/v10/orm/result.go similarity index 88% rename from vendor/github.com/go-pg/pg/orm/result.go rename to vendor/github.com/go-pg/pg/v10/orm/result.go index 6f81245ce..9d82815ef 100644 --- a/vendor/github.com/go-pg/pg/orm/result.go +++ b/vendor/github.com/go-pg/pg/v10/orm/result.go @@ -1,6 +1,6 @@ package orm -// A Result summarizes an executed SQL command. +// Result summarizes an executed SQL command. type Result interface { Model() Model diff --git a/vendor/github.com/go-pg/pg/v10/orm/select.go b/vendor/github.com/go-pg/pg/v10/orm/select.go new file mode 100644 index 000000000..d3b38742d --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/select.go @@ -0,0 +1,346 @@ +package orm + +import ( + "bytes" + "fmt" + "strconv" + "strings" + + "github.com/go-pg/pg/v10/types" +) + +type SelectQuery struct { + q *Query + count string +} + +var ( + _ QueryAppender = (*SelectQuery)(nil) + _ QueryCommand = (*SelectQuery)(nil) +) + +func NewSelectQuery(q *Query) *SelectQuery { + return &SelectQuery{ + q: q, + } +} + +func (q *SelectQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *SelectQuery) Operation() QueryOp { + return SelectOp +} + +func (q *SelectQuery) Clone() QueryCommand { + return &SelectQuery{ + q: q.q.Clone(), + count: q.count, + } +} + +func (q *SelectQuery) Query() *Query { + return q.q +} + +func (q *SelectQuery) AppendTemplate(b []byte) ([]byte, error) { + return q.AppendQuery(dummyFormatter{}, b) +} + +func (q *SelectQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { //nolint:gocyclo + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + + cteCount := q.count != "" && (len(q.q.group) > 0 || q.isDistinct()) + if cteCount { + b = append(b, `WITH "_count_wrapper" AS (`...) + } + + if len(q.q.with) > 0 { + b, err = q.q.appendWith(fmter, b) + if err != nil { + return nil, err + } + } + + if len(q.q.union) > 0 { + b = append(b, '(') + } + + b = append(b, "SELECT "...) + + if len(q.q.distinctOn) > 0 { + b = append(b, "DISTINCT ON ("...) + for i, app := range q.q.distinctOn { + if i > 0 { + b = append(b, ", "...) + } + b, err = app.AppendQuery(fmter, b) + } + b = append(b, ") "...) + } else if q.q.distinctOn != nil { + b = append(b, "DISTINCT "...) + } + + if q.count != "" && !cteCount { + b = append(b, q.count...) + } else { + b, err = q.appendColumns(fmter, b) + if err != nil { + return nil, err + } + } + + if q.q.hasTables() { + b = append(b, " FROM "...) + b, err = q.appendTables(fmter, b) + if err != nil { + return nil, err + } + } + + err = q.q.forEachHasOneJoin(func(j *join) error { + b = append(b, ' ') + b, err = j.appendHasOneJoin(fmter, b, q.q) + return err + }) + if err != nil { + return nil, err + } + + for _, j := range q.q.joins { + b, err = j.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + + if len(q.q.where) > 0 || q.q.isSoftDelete() { + b = append(b, " WHERE "...) + b, err = q.q.appendWhere(fmter, b) + if err != nil { + return nil, err + } + } + + if len(q.q.group) > 0 { + b = append(b, " GROUP BY "...) + for i, f := range q.q.group { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + } + + if len(q.q.having) > 0 { + b = append(b, " HAVING "...) + for i, f := range q.q.having { + if i > 0 { + b = append(b, " AND "...) + } + b = append(b, '(') + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + b = append(b, ')') + } + } + + if q.count == "" { + if len(q.q.order) > 0 { + b = append(b, " ORDER BY "...) + for i, f := range q.q.order { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + } + + if q.q.limit != 0 { + b = append(b, " LIMIT "...) + b = strconv.AppendInt(b, int64(q.q.limit), 10) + } + + if q.q.offset != 0 { + b = append(b, " OFFSET "...) + b = strconv.AppendInt(b, int64(q.q.offset), 10) + } + + if q.q.selFor != nil { + b = append(b, " FOR "...) + b, err = q.q.selFor.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + } else if cteCount { + b = append(b, `) SELECT `...) + b = append(b, q.count...) + b = append(b, ` FROM "_count_wrapper"`...) + } + + if len(q.q.union) > 0 { + b = append(b, ")"...) + + for _, u := range q.q.union { + b = append(b, u.expr...) + b = append(b, '(') + b, err = u.query.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + b = append(b, ")"...) + } + } + + return b, q.q.stickyErr +} + +func (q SelectQuery) appendColumns(fmter QueryFormatter, b []byte) (_ []byte, err error) { + start := len(b) + + switch { + case q.q.columns != nil: + b, err = q.q.appendColumns(fmter, b) + if err != nil { + return nil, err + } + case q.q.hasExplicitTableModel(): + table := q.q.tableModel.Table() + if len(table.Fields) > 10 && isTemplateFormatter(fmter) { + b = append(b, table.Alias...) + b = append(b, '.') + b = types.AppendString(b, fmt.Sprintf("%d columns", len(table.Fields)), 2) + } else { + b = appendColumns(b, table.Alias, table.Fields) + } + default: + b = append(b, '*') + } + + err = q.q.forEachHasOneJoin(func(j *join) error { + if len(b) != start { + b = append(b, ", "...) + start = len(b) + } + + b = j.appendHasOneColumns(b) + return nil + }) + if err != nil { + return nil, err + } + + b = bytes.TrimSuffix(b, []byte(", ")) + + return b, nil +} + +func (q *SelectQuery) isDistinct() bool { + if q.q.distinctOn != nil { + return true + } + for _, column := range q.q.columns { + column, ok := column.(*SafeQueryAppender) + if ok { + if strings.Contains(column.query, "DISTINCT") || + strings.Contains(column.query, "distinct") { + return true + } + } + } + return false +} + +func (q *SelectQuery) appendTables(fmter QueryFormatter, b []byte) (_ []byte, err error) { + tables := q.q.tables + + if q.q.modelHasTableName() { + table := q.q.tableModel.Table() + b = fmter.FormatQuery(b, string(table.SQLNameForSelects)) + if table.Alias != "" { + b = append(b, " AS "...) + b = append(b, table.Alias...) + } + + if len(tables) > 0 { + b = append(b, ", "...) + } + } else if len(tables) > 0 { + b, err = tables[0].AppendQuery(fmter, b) + if err != nil { + return nil, err + } + if q.q.modelHasTableAlias() { + b = append(b, " AS "...) + b = append(b, q.q.tableModel.Table().Alias...) + } + + tables = tables[1:] + if len(tables) > 0 { + b = append(b, ", "...) + } + } + + for i, f := range tables { + if i > 0 { + b = append(b, ", "...) + } + b, err = f.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + + return b, nil +} + +//------------------------------------------------------------------------------ + +type joinQuery struct { + join *SafeQueryAppender + on []*condAppender +} + +func (j *joinQuery) AppendOn(app *condAppender) { + j.on = append(j.on, app) +} + +func (j *joinQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + b = append(b, ' ') + + b, err = j.join.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + + if len(j.on) > 0 { + b = append(b, " ON "...) + for i, on := range j.on { + if i > 0 { + b = on.AppendSep(b) + } + b, err = on.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + } + + return b, nil +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/table.go b/vendor/github.com/go-pg/pg/v10/orm/table.go new file mode 100644 index 000000000..29c1c0c38 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/table.go @@ -0,0 +1,1580 @@ +package orm + +import ( + "database/sql" + "encoding/json" + "fmt" + "net" + "reflect" + "strconv" + "strings" + "sync" + "time" + + "github.com/jinzhu/inflection" + "github.com/vmihailenco/tagparser" + + "github.com/go-pg/zerochecker" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/pgjson" + "github.com/go-pg/pg/v10/types" +) + +const ( + beforeScanHookFlag = uint16(1) << iota + afterScanHookFlag + afterSelectHookFlag + beforeInsertHookFlag + afterInsertHookFlag + beforeUpdateHookFlag + afterUpdateHookFlag + beforeDeleteHookFlag + afterDeleteHookFlag + discardUnknownColumnsFlag +) + +var ( + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + nullTimeType = reflect.TypeOf((*types.NullTime)(nil)).Elem() + sqlNullTimeType = reflect.TypeOf((*sql.NullTime)(nil)).Elem() + ipType = reflect.TypeOf((*net.IP)(nil)).Elem() + ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem() + scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem() + nullBoolType = reflect.TypeOf((*sql.NullBool)(nil)).Elem() + nullFloatType = reflect.TypeOf((*sql.NullFloat64)(nil)).Elem() + nullIntType = reflect.TypeOf((*sql.NullInt64)(nil)).Elem() + nullStringType = reflect.TypeOf((*sql.NullString)(nil)).Elem() + jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem() +) + +var tableNameInflector = inflection.Plural + +// SetTableNameInflector overrides the default func that pluralizes +// model name to get table name, e.g. my_article becomes my_articles. +func SetTableNameInflector(fn func(string) string) { + tableNameInflector = fn +} + +// Table represents a SQL table created from Go struct. +type Table struct { + Type reflect.Type + zeroStruct reflect.Value + + TypeName string + Alias types.Safe + ModelName string + + SQLName types.Safe + SQLNameForSelects types.Safe + + Tablespace types.Safe + + PartitionBy string + + allFields []*Field // read only + skippedFields []*Field + + Fields []*Field // PKs + DataFields + PKs []*Field + DataFields []*Field + fieldsMapMu sync.RWMutex + FieldsMap map[string]*Field + + Methods map[string]*Method + Relations map[string]*Relation + Unique map[string][]*Field + + SoftDeleteField *Field + SetSoftDeleteField func(fv reflect.Value) error + + flags uint16 +} + +func newTable(typ reflect.Type) *Table { + t := new(Table) + t.Type = typ + t.zeroStruct = reflect.New(t.Type).Elem() + t.TypeName = internal.ToExported(t.Type.Name()) + t.ModelName = internal.Underscore(t.Type.Name()) + tableName := tableNameInflector(t.ModelName) + t.setName(quoteIdent(tableName)) + t.Alias = quoteIdent(t.ModelName) + + typ = reflect.PtrTo(t.Type) + if typ.Implements(beforeScanHookType) { + t.setFlag(beforeScanHookFlag) + } + if typ.Implements(afterScanHookType) { + t.setFlag(afterScanHookFlag) + } + if typ.Implements(afterSelectHookType) { + t.setFlag(afterSelectHookFlag) + } + if typ.Implements(beforeInsertHookType) { + t.setFlag(beforeInsertHookFlag) + } + if typ.Implements(afterInsertHookType) { + t.setFlag(afterInsertHookFlag) + } + if typ.Implements(beforeUpdateHookType) { + t.setFlag(beforeUpdateHookFlag) + } + if typ.Implements(afterUpdateHookType) { + t.setFlag(afterUpdateHookFlag) + } + if typ.Implements(beforeDeleteHookType) { + t.setFlag(beforeDeleteHookFlag) + } + if typ.Implements(afterDeleteHookType) { + t.setFlag(afterDeleteHookFlag) + } + + return t +} + +func (t *Table) init1() { + t.initFields() + t.initMethods() +} + +func (t *Table) init2() { + t.initInlines() + t.initRelations() + t.skippedFields = nil +} + +func (t *Table) setName(name types.Safe) { + t.SQLName = name + t.SQLNameForSelects = name + if t.Alias == "" { + t.Alias = name + } +} + +func (t *Table) String() string { + return "model=" + t.TypeName +} + +func (t *Table) setFlag(flag uint16) { + t.flags |= flag +} + +func (t *Table) hasFlag(flag uint16) bool { + if t == nil { + return false + } + return t.flags&flag != 0 +} + +func (t *Table) checkPKs() error { + if len(t.PKs) == 0 { + return fmt.Errorf("pg: %s does not have primary keys", t) + } + return nil +} + +func (t *Table) mustSoftDelete() error { + if t.SoftDeleteField == nil { + return fmt.Errorf("pg: %s does not support soft deletes", t) + } + return nil +} + +func (t *Table) AddField(field *Field) { + t.Fields = append(t.Fields, field) + if field.hasFlag(PrimaryKeyFlag) { + t.PKs = append(t.PKs, field) + } else { + t.DataFields = append(t.DataFields, field) + } + t.FieldsMap[field.SQLName] = field +} + +func (t *Table) RemoveField(field *Field) { + t.Fields = removeField(t.Fields, field) + if field.hasFlag(PrimaryKeyFlag) { + t.PKs = removeField(t.PKs, field) + } else { + t.DataFields = removeField(t.DataFields, field) + } + delete(t.FieldsMap, field.SQLName) +} + +func removeField(fields []*Field, field *Field) []*Field { + for i, f := range fields { + if f == field { + fields = append(fields[:i], fields[i+1:]...) + } + } + return fields +} + +func (t *Table) getField(name string) *Field { + t.fieldsMapMu.RLock() + field := t.FieldsMap[name] + t.fieldsMapMu.RUnlock() + return field +} + +func (t *Table) HasField(name string) bool { + _, ok := t.FieldsMap[name] + return ok +} + +func (t *Table) GetField(name string) (*Field, error) { + field, ok := t.FieldsMap[name] + if !ok { + return nil, fmt.Errorf("pg: %s does not have column=%s", t, name) + } + return field, nil +} + +func (t *Table) AppendParam(b []byte, strct reflect.Value, name string) ([]byte, bool) { + field, ok := t.FieldsMap[name] + if ok { + b = field.AppendValue(b, strct, 1) + return b, true + } + + method, ok := t.Methods[name] + if ok { + b = method.AppendValue(b, strct.Addr(), 1) + return b, true + } + + return b, false +} + +func (t *Table) initFields() { + t.Fields = make([]*Field, 0, t.Type.NumField()) + t.FieldsMap = make(map[string]*Field, t.Type.NumField()) + t.addFields(t.Type, nil) +} + +func (t *Table) addFields(typ reflect.Type, baseIndex []int) { + for i := 0; i < typ.NumField(); i++ { + f := typ.Field(i) + + // Make a copy so slice is not shared between fields. + index := make([]int, len(baseIndex)) + copy(index, baseIndex) + + if f.Anonymous { + if f.Tag.Get("sql") == "-" || f.Tag.Get("pg") == "-" { + continue + } + + fieldType := indirectType(f.Type) + if fieldType.Kind() != reflect.Struct { + continue + } + t.addFields(fieldType, append(index, f.Index...)) + + pgTag := tagparser.Parse(f.Tag.Get("pg")) + if _, inherit := pgTag.Options["inherit"]; inherit { + embeddedTable := _tables.get(fieldType, true) + t.TypeName = embeddedTable.TypeName + t.SQLName = embeddedTable.SQLName + t.SQLNameForSelects = embeddedTable.SQLNameForSelects + t.Alias = embeddedTable.Alias + t.ModelName = embeddedTable.ModelName + } + + continue + } + + field := t.newField(f, index) + if field != nil { + t.AddField(field) + } + } +} + +//nolint +func (t *Table) newField(f reflect.StructField, index []int) *Field { + pgTag := tagparser.Parse(f.Tag.Get("pg")) + + switch f.Name { + case "tableName": + if len(index) > 0 { + return nil + } + + if isKnownTableOption(pgTag.Name) { + internal.Warn.Printf( + "%s.%s tag name %q is also an option name; is it a mistake?", + t.TypeName, f.Name, pgTag.Name, + ) + } + + for name := range pgTag.Options { + if !isKnownTableOption(name) { + internal.Warn.Printf("%s.%s has unknown tag option: %q", t.TypeName, f.Name, name) + } + } + + if tableSpace, ok := pgTag.Options["tablespace"]; ok { + s, _ := tagparser.Unquote(tableSpace) + t.Tablespace = quoteIdent(s) + } + + partitionBy, ok := pgTag.Options["partition_by"] + if !ok { + partitionBy, ok = pgTag.Options["partitionBy"] + if ok { + internal.Deprecated.Printf("partitionBy is renamed to partition_by") + } + } + if ok { + s, _ := tagparser.Unquote(partitionBy) + t.PartitionBy = s + } + + if pgTag.Name == "_" { + t.setName("") + } else if pgTag.Name != "" { + s, _ := tagparser.Unquote(pgTag.Name) + t.setName(types.Safe(quoteTableName(s))) + } + + if s, ok := pgTag.Options["select"]; ok { + s, _ = tagparser.Unquote(s) + t.SQLNameForSelects = types.Safe(quoteTableName(s)) + } + + if v, ok := pgTag.Options["alias"]; ok { + v, _ = tagparser.Unquote(v) + t.Alias = quoteIdent(v) + } + + pgTag := tagparser.Parse(f.Tag.Get("pg")) + if _, ok := pgTag.Options["discard_unknown_columns"]; ok { + t.setFlag(discardUnknownColumnsFlag) + } + + return nil + } + + if f.PkgPath != "" { + return nil + } + + sqlName := internal.Underscore(f.Name) + + if pgTag.Name != sqlName && isKnownFieldOption(pgTag.Name) { + internal.Warn.Printf( + "%s.%s tag name %q is also an option name; is it a mistake?", + t.TypeName, f.Name, pgTag.Name, + ) + } + + for name := range pgTag.Options { + if !isKnownFieldOption(name) { + internal.Warn.Printf("%s.%s has unknown tag option: %q", t.TypeName, f.Name, name) + } + } + + skip := pgTag.Name == "-" + if !skip && pgTag.Name != "" { + sqlName = pgTag.Name + } + + index = append(index, f.Index...) + if field := t.getField(sqlName); field != nil { + if indexEqual(field.Index, index) { + return field + } + t.RemoveField(field) + } + + field := &Field{ + Field: f, + Type: indirectType(f.Type), + + GoName: f.Name, + SQLName: sqlName, + Column: quoteIdent(sqlName), + + Index: index, + } + + if _, ok := pgTag.Options["notnull"]; ok { + field.setFlag(NotNullFlag) + } + if v, ok := pgTag.Options["unique"]; ok { + if v == "" { + field.setFlag(UniqueFlag) + } + // Split the value by comma, this will allow multiple names to be specified. + // We can use this to create multiple named unique constraints where a single column + // might be included in multiple constraints. + v, _ = tagparser.Unquote(v) + for _, uniqueName := range strings.Split(v, ",") { + if t.Unique == nil { + t.Unique = make(map[string][]*Field) + } + t.Unique[uniqueName] = append(t.Unique[uniqueName], field) + } + } + if v, ok := pgTag.Options["default"]; ok { + v, ok = tagparser.Unquote(v) + if ok { + field.Default = types.Safe(types.AppendString(nil, v, 1)) + } else { + field.Default = types.Safe(v) + } + } + + //nolint + if _, ok := pgTag.Options["pk"]; ok { + field.setFlag(PrimaryKeyFlag) + } else if strings.HasSuffix(field.SQLName, "_id") || + strings.HasSuffix(field.SQLName, "_uuid") { + field.setFlag(ForeignKeyFlag) + } else if strings.HasPrefix(field.SQLName, "fk_") { + field.setFlag(ForeignKeyFlag) + } else if len(t.PKs) == 0 && !pgTag.HasOption("nopk") { + switch field.SQLName { + case "id", "uuid", "pk_" + t.ModelName: + field.setFlag(PrimaryKeyFlag) + } + } + + if _, ok := pgTag.Options["use_zero"]; ok { + field.setFlag(UseZeroFlag) + } + if _, ok := pgTag.Options["array"]; ok { + field.setFlag(ArrayFlag) + } + + field.SQLType = fieldSQLType(field, pgTag) + if strings.HasSuffix(field.SQLType, "[]") { + field.setFlag(ArrayFlag) + } + + if v, ok := pgTag.Options["on_delete"]; ok { + field.OnDelete = v + } + + if v, ok := pgTag.Options["on_update"]; ok { + field.OnUpdate = v + } + + if _, ok := pgTag.Options["composite"]; ok { + field.append = compositeAppender(f.Type) + field.scan = compositeScanner(f.Type) + } else if _, ok := pgTag.Options["json_use_number"]; ok { + field.append = types.Appender(f.Type) + field.scan = scanJSONValue + } else if field.hasFlag(ArrayFlag) { + field.append = types.ArrayAppender(f.Type) + field.scan = types.ArrayScanner(f.Type) + } else if _, ok := pgTag.Options["hstore"]; ok { + field.append = types.HstoreAppender(f.Type) + field.scan = types.HstoreScanner(f.Type) + } else if field.SQLType == pgTypeBigint && field.Type.Kind() == reflect.Uint64 { + if f.Type.Kind() == reflect.Ptr { + field.append = appendUintPtrAsInt + } else { + field.append = appendUintAsInt + } + field.scan = types.Scanner(f.Type) + } else if _, ok := pgTag.Options["msgpack"]; ok { + field.append = msgpackAppender(f.Type) + field.scan = msgpackScanner(f.Type) + } else { + field.append = types.Appender(f.Type) + field.scan = types.Scanner(f.Type) + } + field.isZero = zerochecker.Checker(f.Type) + + if v, ok := pgTag.Options["alias"]; ok { + v, _ = tagparser.Unquote(v) + t.FieldsMap[v] = field + } + + t.allFields = append(t.allFields, field) + if skip { + t.skippedFields = append(t.skippedFields, field) + t.FieldsMap[field.SQLName] = field + return nil + } + + if _, ok := pgTag.Options["soft_delete"]; ok { + t.SetSoftDeleteField = setSoftDeleteFieldFunc(f.Type) + if t.SetSoftDeleteField == nil { + err := fmt.Errorf( + "pg: soft_delete is only supported for time.Time, pg.NullTime, sql.NullInt64, and int64 (or implement ValueScanner that scans time)") + panic(err) + } + t.SoftDeleteField = field + } + + return field +} + +func (t *Table) initMethods() { + t.Methods = make(map[string]*Method) + typ := reflect.PtrTo(t.Type) + for i := 0; i < typ.NumMethod(); i++ { + m := typ.Method(i) + if m.PkgPath != "" { + continue + } + if m.Type.NumIn() > 1 { + continue + } + if m.Type.NumOut() != 1 { + continue + } + + retType := m.Type.Out(0) + t.Methods[m.Name] = &Method{ + Index: m.Index, + + appender: types.Appender(retType), + } + } +} + +func (t *Table) initInlines() { + for _, f := range t.skippedFields { + if f.Type.Kind() == reflect.Struct { + t.inlineFields(f, nil) + } + } +} + +func (t *Table) initRelations() { + for i := 0; i < len(t.Fields); { + f := t.Fields[i] + if t.tryRelation(f) { + t.Fields = removeField(t.Fields, f) + t.DataFields = removeField(t.DataFields, f) + } else { + i++ + } + + if f.Type.Kind() == reflect.Struct { + t.inlineFields(f, nil) + } + } +} + +func (t *Table) tryRelation(field *Field) bool { + pgTag := tagparser.Parse(field.Field.Tag.Get("pg")) + + if rel, ok := pgTag.Options["rel"]; ok { + return t.tryRelationType(field, rel, pgTag) + } + if _, ok := pgTag.Options["many2many"]; ok { + return t.tryRelationType(field, "many2many", pgTag) + } + + if field.UserSQLType != "" || isScanner(field.Type) { + return false + } + + switch field.Type.Kind() { + case reflect.Slice: + return t.tryRelationSlice(field, pgTag) + case reflect.Struct: + return t.tryRelationStruct(field, pgTag) + } + return false +} + +func (t *Table) tryRelationType(field *Field, rel string, pgTag *tagparser.Tag) bool { + switch rel { + case "has-one": + return t.mustHasOneRelation(field, pgTag) + case "belongs-to": + return t.mustBelongsToRelation(field, pgTag) + case "has-many": + return t.mustHasManyRelation(field, pgTag) + case "many2many": + return t.mustM2MRelation(field, pgTag) + default: + panic(fmt.Errorf("pg: unknown relation=%s on field=%s", rel, field.GoName)) + } +} + +func (t *Table) mustHasOneRelation(field *Field, pgTag *tagparser.Tag) bool { + joinTable := _tables.get(field.Type, true) + joinPKs := joinTable.PKs + + joinFKPrefix, joinFKOK := pgTag.Options["join_fk"] + + if err := joinTable.checkPKs(); err != nil && !joinFKOK { + // join performed by primary key if join_fk not specified + // so join table must have primary key + panic(err) + } + + if joinFKOK { + joinField := joinTable.getField(joinFKPrefix) + if joinField == nil { + panic(fmt.Errorf( + "pg: %s has-one %s: field %s specified by join_fk doesn't exist on %s", + t.TypeName, field.GoName, joinFKPrefix, joinTable.TypeName, + )) + } + + joinPKs = []*Field{joinField} + } + + fkPrefix, fkOK := pgTag.Options["fk"] + + if fkOK && len(joinPKs) == 1 { + fk := t.getField(fkPrefix) + if fk == nil { + panic(fmt.Errorf( + "pg: %s has-one %s: %s must have column %s "+ + "(use fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, t.TypeName, fkPrefix, field.GoName, + )) + } + + t.addRelation(&Relation{ + Type: HasOneRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: []*Field{fk}, + JoinFKs: joinPKs, + }) + return true + } + + if !fkOK { + fkPrefix = internal.Underscore(field.GoName) + "_" + } + fks := make([]*Field, 0, len(joinPKs)) + + for _, joinPK := range joinPKs { + fkName := fkPrefix + joinPK.SQLName + if fk := t.getField(fkName); fk != nil { + fks = append(fks, fk) + continue + } + + if fk := t.getField(joinPK.SQLName); fk != nil { + fks = append(fks, fk) + continue + } + + panic(fmt.Errorf( + "pg: %s has-one %s: %s must have column %s "+ + "(use fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, t.TypeName, fkName, field.GoName, + )) + } + + t.addRelation(&Relation{ + Type: HasOneRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: fks, + JoinFKs: joinPKs, + }) + return true +} + +func (t *Table) mustBelongsToRelation(field *Field, pgTag *tagparser.Tag) bool { + if err := t.checkPKs(); err != nil { + panic(err) + } + joinTable := _tables.get(field.Type, true) + fkPrefix, fkOK := pgTag.Options["join_fk"] + + if fkOK && len(t.PKs) == 1 { + fk := joinTable.getField(fkPrefix) + if fk == nil { + panic(fmt.Errorf( + "pg: %s belongs-to %s: %s must have column %s "+ + "(use join_fk:custom_column tag on %s field to specify custom column)", + field.GoName, t.TypeName, joinTable.TypeName, fkPrefix, field.GoName, + )) + } + + t.addRelation(&Relation{ + Type: BelongsToRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: t.PKs, + JoinFKs: []*Field{fk}, + }) + return true + } + + if !fkOK { + fkPrefix = internal.Underscore(t.ModelName) + "_" + } + fks := make([]*Field, 0, len(t.PKs)) + + for _, pk := range t.PKs { + fkName := fkPrefix + pk.SQLName + if fk := joinTable.getField(fkName); fk != nil { + fks = append(fks, fk) + continue + } + + if fk := joinTable.getField(pk.SQLName); fk != nil { + fks = append(fks, fk) + continue + } + + panic(fmt.Errorf( + "pg: %s belongs-to %s: %s must have column %s "+ + "(use join_fk:custom_column tag on %s field to specify custom column)", + field.GoName, t.TypeName, joinTable.TypeName, fkName, field.GoName, + )) + } + + t.addRelation(&Relation{ + Type: BelongsToRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: t.PKs, + JoinFKs: fks, + }) + return true +} + +func (t *Table) mustHasManyRelation(field *Field, pgTag *tagparser.Tag) bool { + if err := t.checkPKs(); err != nil { + panic(err) + } + if field.Type.Kind() != reflect.Slice { + panic(fmt.Errorf( + "pg: %s.%s has-many relation requires slice, got %q", + t.TypeName, field.GoName, field.Type.Kind(), + )) + } + + joinTable := _tables.get(indirectType(field.Type.Elem()), true) + fkPrefix, fkOK := pgTag.Options["join_fk"] + _, polymorphic := pgTag.Options["polymorphic"] + + if fkOK && !polymorphic && len(t.PKs) == 1 { + fk := joinTable.getField(fkPrefix) + if fk == nil { + panic(fmt.Errorf( + "pg: %s has-many %s: %s must have column %s "+ + "(use join_fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, joinTable.TypeName, fkPrefix, field.GoName, + )) + } + + t.addRelation(&Relation{ + Type: HasManyRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: t.PKs, + JoinFKs: []*Field{fk}, + }) + return true + } + + if !fkOK { + fkPrefix = internal.Underscore(t.ModelName) + "_" + } + fks := make([]*Field, 0, len(t.PKs)) + + for _, pk := range t.PKs { + fkName := fkPrefix + pk.SQLName + if fk := joinTable.getField(fkName); fk != nil { + fks = append(fks, fk) + continue + } + + if fk := joinTable.getField(pk.SQLName); fk != nil { + fks = append(fks, fk) + continue + } + + panic(fmt.Errorf( + "pg: %s has-many %s: %s must have column %s "+ + "(use join_fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, joinTable.TypeName, fkName, field.GoName, + )) + } + + var typeField *Field + + if polymorphic { + typeFieldName := fkPrefix + "type" + typeField = joinTable.getField(typeFieldName) + if typeField == nil { + panic(fmt.Errorf( + "pg: %s has-many %s: %s must have polymorphic column %s", + t.TypeName, field.GoName, joinTable.TypeName, typeFieldName, + )) + } + } + + t.addRelation(&Relation{ + Type: HasManyRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: t.PKs, + JoinFKs: fks, + Polymorphic: typeField, + }) + return true +} + +func (t *Table) mustM2MRelation(field *Field, pgTag *tagparser.Tag) bool { + if field.Type.Kind() != reflect.Slice { + panic(fmt.Errorf( + "pg: %s.%s many2many relation requires slice, got %q", + t.TypeName, field.GoName, field.Type.Kind(), + )) + } + joinTable := _tables.get(indirectType(field.Type.Elem()), true) + + if err := t.checkPKs(); err != nil { + panic(err) + } + if err := joinTable.checkPKs(); err != nil { + panic(err) + } + + m2mTableNameString, ok := pgTag.Options["many2many"] + if !ok { + panic(fmt.Errorf("pg: %s must have many2many tag option", field.GoName)) + } + m2mTableName := quoteTableName(m2mTableNameString) + + m2mTable := _tables.getByName(m2mTableName) + if m2mTable == nil { + panic(fmt.Errorf( + "pg: can't find %s table (use orm.RegisterTable to register the model)", + m2mTableName, + )) + } + + var baseFKs []string + var joinFKs []string + + { + fkPrefix, ok := pgTag.Options["fk"] + if !ok { + fkPrefix = internal.Underscore(t.ModelName) + "_" + } + + if ok && len(t.PKs) == 1 { + if m2mTable.getField(fkPrefix) == nil { + panic(fmt.Errorf( + "pg: %s many2many %s: %s must have column %s "+ + "(use fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, m2mTable.TypeName, fkPrefix, field.GoName, + )) + } + baseFKs = []string{fkPrefix} + } else { + for _, pk := range t.PKs { + fkName := fkPrefix + pk.SQLName + if m2mTable.getField(fkName) != nil { + baseFKs = append(baseFKs, fkName) + continue + } + + if m2mTable.getField(pk.SQLName) != nil { + baseFKs = append(baseFKs, pk.SQLName) + continue + } + + panic(fmt.Errorf( + "pg: %s many2many %s: %s must have column %s "+ + "(use fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, m2mTable.TypeName, fkName, field.GoName, + )) + } + } + } + + { + joinFKPrefix, ok := pgTag.Options["join_fk"] + if !ok { + joinFKPrefix = internal.Underscore(joinTable.ModelName) + "_" + } + + if ok && len(joinTable.PKs) == 1 { + if m2mTable.getField(joinFKPrefix) == nil { + panic(fmt.Errorf( + "pg: %s many2many %s: %s must have column %s "+ + "(use join_fk:custom_column tag on %s field to specify custom column)", + joinTable.TypeName, field.GoName, m2mTable.TypeName, joinFKPrefix, field.GoName, + )) + } + joinFKs = []string{joinFKPrefix} + } else { + for _, joinPK := range joinTable.PKs { + fkName := joinFKPrefix + joinPK.SQLName + if m2mTable.getField(fkName) != nil { + joinFKs = append(joinFKs, fkName) + continue + } + + if m2mTable.getField(joinPK.SQLName) != nil { + joinFKs = append(joinFKs, joinPK.SQLName) + continue + } + + panic(fmt.Errorf( + "pg: %s many2many %s: %s must have column %s "+ + "(use join_fk:custom_column tag on %s field to specify custom column)", + t.TypeName, field.GoName, m2mTable.TypeName, fkName, field.GoName, + )) + } + } + } + + t.addRelation(&Relation{ + Type: Many2ManyRelation, + Field: field, + JoinTable: joinTable, + M2MTableName: m2mTableName, + M2MTableAlias: m2mTable.Alias, + M2MBaseFKs: baseFKs, + M2MJoinFKs: joinFKs, + }) + return true +} + +//nolint +func (t *Table) tryRelationSlice(field *Field, pgTag *tagparser.Tag) bool { + if t.tryM2MRelation(field, pgTag) { + internal.Deprecated.Printf( + `add pg:"rel:many2many" to %s.%s field tag`, t.TypeName, field.GoName) + return true + } + if t.tryHasManyRelation(field, pgTag) { + internal.Deprecated.Printf( + `add pg:"rel:has-many" to %s.%s field tag`, t.TypeName, field.GoName) + return true + } + return false +} + +func (t *Table) tryM2MRelation(field *Field, pgTag *tagparser.Tag) bool { + elemType := indirectType(field.Type.Elem()) + if elemType.Kind() != reflect.Struct { + return false + } + + joinTable := _tables.get(elemType, true) + + fk, fkOK := pgTag.Options["fk"] + if fkOK { + if fk == "-" { + return false + } + fk = tryUnderscorePrefix(fk) + } + + m2mTableName := pgTag.Options["many2many"] + if m2mTableName == "" { + return false + } + + m2mTable := _tables.getByName(quoteIdent(m2mTableName)) + + var m2mTableAlias types.Safe + if m2mTable != nil { + m2mTableAlias = m2mTable.Alias + } else if ind := strings.IndexByte(m2mTableName, '.'); ind >= 0 { + m2mTableAlias = quoteIdent(m2mTableName[ind+1:]) + } else { + m2mTableAlias = quoteIdent(m2mTableName) + } + + var fks []string + if !fkOK { + fk = t.ModelName + "_" + } + if m2mTable != nil { + keys := foreignKeys(t, m2mTable, fk, fkOK) + if len(keys) == 0 { + return false + } + for _, fk := range keys { + fks = append(fks, fk.SQLName) + } + } else { + if fkOK && len(t.PKs) == 1 { + fks = append(fks, fk) + } else { + for _, pk := range t.PKs { + fks = append(fks, fk+pk.SQLName) + } + } + } + + joinFK, joinFKOk := pgTag.Options["join_fk"] + if !joinFKOk { + joinFK, joinFKOk = pgTag.Options["joinFK"] + if joinFKOk { + internal.Deprecated.Printf("joinFK is renamed to join_fk") + } + } + if joinFKOk { + joinFK = tryUnderscorePrefix(joinFK) + } else { + joinFK = joinTable.ModelName + "_" + } + + var joinFKs []string + if m2mTable != nil { + keys := foreignKeys(joinTable, m2mTable, joinFK, joinFKOk) + if len(keys) == 0 { + return false + } + for _, fk := range keys { + joinFKs = append(joinFKs, fk.SQLName) + } + } else { + if joinFKOk && len(joinTable.PKs) == 1 { + joinFKs = append(joinFKs, joinFK) + } else { + for _, pk := range joinTable.PKs { + joinFKs = append(joinFKs, joinFK+pk.SQLName) + } + } + } + + t.addRelation(&Relation{ + Type: Many2ManyRelation, + Field: field, + JoinTable: joinTable, + M2MTableName: quoteIdent(m2mTableName), + M2MTableAlias: m2mTableAlias, + M2MBaseFKs: fks, + M2MJoinFKs: joinFKs, + }) + return true +} + +func (t *Table) tryHasManyRelation(field *Field, pgTag *tagparser.Tag) bool { + elemType := indirectType(field.Type.Elem()) + if elemType.Kind() != reflect.Struct { + return false + } + + joinTable := _tables.get(elemType, true) + + fk, fkOK := pgTag.Options["fk"] + if fkOK { + if fk == "-" { + return false + } + fk = tryUnderscorePrefix(fk) + } + + s, polymorphic := pgTag.Options["polymorphic"] + var typeField *Field + if polymorphic { + fk = tryUnderscorePrefix(s) + + typeField = joinTable.getField(fk + "type") + if typeField == nil { + return false + } + } else if !fkOK { + fk = t.ModelName + "_" + } + + fks := foreignKeys(t, joinTable, fk, fkOK || polymorphic) + if len(fks) == 0 { + return false + } + + var fkValues []*Field + fkValue, ok := pgTag.Options["fk_value"] + if ok { + if len(fks) > 1 { + panic(fmt.Errorf("got fk_value, but there are %d fks", len(fks))) + } + + f := t.getField(fkValue) + if f == nil { + panic(fmt.Errorf("fk_value=%q not found in %s", fkValue, t)) + } + fkValues = append(fkValues, f) + } else { + fkValues = t.PKs + } + + if len(fks) != len(fkValues) { + panic("len(fks) != len(fkValues)") + } + + if len(fks) > 0 { + t.addRelation(&Relation{ + Type: HasManyRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: fkValues, + JoinFKs: fks, + Polymorphic: typeField, + }) + return true + } + + return false +} + +func (t *Table) tryRelationStruct(field *Field, pgTag *tagparser.Tag) bool { + joinTable := _tables.get(field.Type, true) + + if len(joinTable.allFields) == 0 { + return false + } + + if t.tryHasOne(joinTable, field, pgTag) { + internal.Deprecated.Printf( + `add pg:"rel:has-one" to %s.%s field tag`, t.TypeName, field.GoName) + t.inlineFields(field, nil) + return true + } + + if t.tryBelongsToOne(joinTable, field, pgTag) { + internal.Deprecated.Printf( + `add pg:"rel:belongs-to" to %s.%s field tag`, t.TypeName, field.GoName) + t.inlineFields(field, nil) + return true + } + + t.inlineFields(field, nil) + return false +} + +func (t *Table) inlineFields(strct *Field, path map[reflect.Type]struct{}) { + if path == nil { + path = map[reflect.Type]struct{}{ + t.Type: {}, + } + } + + if _, ok := path[strct.Type]; ok { + return + } + path[strct.Type] = struct{}{} + + joinTable := _tables.get(strct.Type, true) + for _, f := range joinTable.allFields { + f = f.Clone() + f.GoName = strct.GoName + "_" + f.GoName + f.SQLName = strct.SQLName + "__" + f.SQLName + f.Column = quoteIdent(f.SQLName) + f.Index = appendNew(strct.Index, f.Index...) + + t.fieldsMapMu.Lock() + if _, ok := t.FieldsMap[f.SQLName]; !ok { + t.FieldsMap[f.SQLName] = f + } + t.fieldsMapMu.Unlock() + + if f.Type.Kind() != reflect.Struct { + continue + } + + if _, ok := path[f.Type]; !ok { + t.inlineFields(f, path) + } + } +} + +func appendNew(dst []int, src ...int) []int { + cp := make([]int, len(dst)+len(src)) + copy(cp, dst) + copy(cp[len(dst):], src) + return cp +} + +func isScanner(typ reflect.Type) bool { + return typ.Implements(scannerType) || reflect.PtrTo(typ).Implements(scannerType) +} + +func fieldSQLType(field *Field, pgTag *tagparser.Tag) string { + if typ, ok := pgTag.Options["type"]; ok { + typ, _ = tagparser.Unquote(typ) + field.UserSQLType = typ + typ = normalizeSQLType(typ) + return typ + } + + if typ, ok := pgTag.Options["composite"]; ok { + typ, _ = tagparser.Unquote(typ) + return typ + } + + if _, ok := pgTag.Options["hstore"]; ok { + return "hstore" + } else if _, ok := pgTag.Options["hstore"]; ok { + return "hstore" + } + + if field.hasFlag(ArrayFlag) { + switch field.Type.Kind() { + case reflect.Slice, reflect.Array: + sqlType := sqlType(field.Type.Elem()) + return sqlType + "[]" + } + } + + sqlType := sqlType(field.Type) + return sqlType +} + +func sqlType(typ reflect.Type) string { + switch typ { + case timeType, nullTimeType, sqlNullTimeType: + return pgTypeTimestampTz + case ipType: + return pgTypeInet + case ipNetType: + return pgTypeCidr + case nullBoolType: + return pgTypeBoolean + case nullFloatType: + return pgTypeDoublePrecision + case nullIntType: + return pgTypeBigint + case nullStringType: + return pgTypeText + case jsonRawMessageType: + return pgTypeJSONB + } + + switch typ.Kind() { + case reflect.Int8, reflect.Uint8, reflect.Int16: + return pgTypeSmallint + case reflect.Uint16, reflect.Int32: + return pgTypeInteger + case reflect.Uint32, reflect.Int64, reflect.Int: + return pgTypeBigint + case reflect.Uint, reflect.Uint64: + // Unsigned bigint is not supported - use bigint. + return pgTypeBigint + case reflect.Float32: + return pgTypeReal + case reflect.Float64: + return pgTypeDoublePrecision + case reflect.Bool: + return pgTypeBoolean + case reflect.String: + return pgTypeText + case reflect.Map, reflect.Struct: + return pgTypeJSONB + case reflect.Array, reflect.Slice: + if typ.Elem().Kind() == reflect.Uint8 { + return pgTypeBytea + } + return pgTypeJSONB + default: + return typ.Kind().String() + } +} + +func normalizeSQLType(s string) string { + switch s { + case "int2": + return pgTypeSmallint + case "int4", "int", "serial": + return pgTypeInteger + case "int8", pgTypeBigserial: + return pgTypeBigint + case "float4": + return pgTypeReal + case "float8": + return pgTypeDoublePrecision + } + return s +} + +func sqlTypeEqual(a, b string) bool { + return a == b +} + +func (t *Table) tryHasOne(joinTable *Table, field *Field, pgTag *tagparser.Tag) bool { + fk, fkOK := pgTag.Options["fk"] + if fkOK { + if fk == "-" { + return false + } + fk = tryUnderscorePrefix(fk) + } else { + fk = internal.Underscore(field.GoName) + "_" + } + + fks := foreignKeys(joinTable, t, fk, fkOK) + if len(fks) > 0 { + t.addRelation(&Relation{ + Type: HasOneRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: fks, + JoinFKs: joinTable.PKs, + }) + return true + } + return false +} + +func (t *Table) tryBelongsToOne(joinTable *Table, field *Field, pgTag *tagparser.Tag) bool { + fk, fkOK := pgTag.Options["fk"] + if fkOK { + if fk == "-" { + return false + } + fk = tryUnderscorePrefix(fk) + } else { + fk = internal.Underscore(t.TypeName) + "_" + } + + fks := foreignKeys(t, joinTable, fk, fkOK) + if len(fks) > 0 { + t.addRelation(&Relation{ + Type: BelongsToRelation, + Field: field, + JoinTable: joinTable, + BaseFKs: t.PKs, + JoinFKs: fks, + }) + return true + } + return false +} + +func (t *Table) addRelation(rel *Relation) { + if t.Relations == nil { + t.Relations = make(map[string]*Relation) + } + _, ok := t.Relations[rel.Field.GoName] + if ok { + panic(fmt.Errorf("%s already has %s", t, rel)) + } + t.Relations[rel.Field.GoName] = rel +} + +func foreignKeys(base, join *Table, fk string, tryFK bool) []*Field { + var fks []*Field + + for _, pk := range base.PKs { + fkName := fk + pk.SQLName + f := join.getField(fkName) + if f != nil && sqlTypeEqual(pk.SQLType, f.SQLType) { + fks = append(fks, f) + continue + } + + if strings.IndexByte(pk.SQLName, '_') == -1 { + continue + } + + f = join.getField(pk.SQLName) + if f != nil && sqlTypeEqual(pk.SQLType, f.SQLType) { + fks = append(fks, f) + continue + } + } + if len(fks) > 0 && len(fks) == len(base.PKs) { + return fks + } + + fks = nil + for _, pk := range base.PKs { + if !strings.HasPrefix(pk.SQLName, "pk_") { + continue + } + fkName := "fk_" + pk.SQLName[3:] + f := join.getField(fkName) + if f != nil && sqlTypeEqual(pk.SQLType, f.SQLType) { + fks = append(fks, f) + } + } + if len(fks) > 0 && len(fks) == len(base.PKs) { + return fks + } + + if fk == "" || len(base.PKs) != 1 { + return nil + } + + if tryFK { + f := join.getField(fk) + if f != nil && sqlTypeEqual(base.PKs[0].SQLType, f.SQLType) { + return []*Field{f} + } + } + + for _, suffix := range []string{"id", "uuid"} { + f := join.getField(fk + suffix) + if f != nil && sqlTypeEqual(base.PKs[0].SQLType, f.SQLType) { + return []*Field{f} + } + } + + return nil +} + +func scanJSONValue(v reflect.Value, rd types.Reader, n int) error { + // Zero value so it works with SelectOrInsert. + // TODO: better handle slices + v.Set(reflect.New(v.Type()).Elem()) + + if n == -1 { + return nil + } + + dec := pgjson.NewDecoder(rd) + dec.UseNumber() + return dec.Decode(v.Addr().Interface()) +} + +func appendUintAsInt(b []byte, v reflect.Value, _ int) []byte { + return strconv.AppendInt(b, int64(v.Uint()), 10) +} + +func appendUintPtrAsInt(b []byte, v reflect.Value, _ int) []byte { + return strconv.AppendInt(b, int64(v.Elem().Uint()), 10) +} + +func tryUnderscorePrefix(s string) string { + if s == "" { + return s + } + if c := s[0]; internal.IsUpper(c) { + return internal.Underscore(s) + "_" + } + return s +} + +func quoteTableName(s string) types.Safe { + // Don't quote if table name contains placeholder (?) or parentheses. + if strings.IndexByte(s, '?') >= 0 || + strings.IndexByte(s, '(') >= 0 && strings.IndexByte(s, ')') >= 0 { + return types.Safe(s) + } + return quoteIdent(s) +} + +func quoteIdent(s string) types.Safe { + return types.Safe(types.AppendIdent(nil, s, 1)) +} + +func setSoftDeleteFieldFunc(typ reflect.Type) func(fv reflect.Value) error { + switch typ { + case timeType: + return func(fv reflect.Value) error { + ptr := fv.Addr().Interface().(*time.Time) + *ptr = time.Now() + return nil + } + case nullTimeType: + return func(fv reflect.Value) error { + ptr := fv.Addr().Interface().(*types.NullTime) + *ptr = types.NullTime{Time: time.Now()} + return nil + } + case nullIntType: + return func(fv reflect.Value) error { + ptr := fv.Addr().Interface().(*sql.NullInt64) + *ptr = sql.NullInt64{Int64: time.Now().UnixNano()} + return nil + } + } + + switch typ.Kind() { + case reflect.Int64: + return func(fv reflect.Value) error { + ptr := fv.Addr().Interface().(*int64) + *ptr = time.Now().UnixNano() + return nil + } + case reflect.Ptr: + break + default: + return setSoftDeleteFallbackFunc(typ) + } + + originalType := typ + typ = typ.Elem() + + switch typ { //nolint:gocritic + case timeType: + return func(fv reflect.Value) error { + now := time.Now() + fv.Set(reflect.ValueOf(&now)) + return nil + } + } + + switch typ.Kind() { //nolint:gocritic + case reflect.Int64: + return func(fv reflect.Value) error { + utime := time.Now().UnixNano() + fv.Set(reflect.ValueOf(&utime)) + return nil + } + } + + return setSoftDeleteFallbackFunc(originalType) +} + +func setSoftDeleteFallbackFunc(typ reflect.Type) func(fv reflect.Value) error { + scanner := types.Scanner(typ) + if scanner == nil { + return nil + } + + return func(fv reflect.Value) error { + var flags int + b := types.AppendTime(nil, time.Now(), flags) + return scanner(fv, pool.NewBytesReader(b), len(b)) + } +} + +func isKnownTableOption(name string) bool { + switch name { + case "alias", + "select", + "tablespace", + "partition_by", + "discard_unknown_columns": + return true + } + return false +} + +func isKnownFieldOption(name string) bool { + switch name { + case "alias", + "type", + "array", + "hstore", + "composite", + "json_use_number", + "msgpack", + "notnull", + "use_zero", + "default", + "unique", + "soft_delete", + "on_delete", + "on_update", + + "pk", + "nopk", + "rel", + "fk", + "join_fk", + "many2many", + "polymorphic": + return true + } + return false +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/table_create.go b/vendor/github.com/go-pg/pg/v10/orm/table_create.go new file mode 100644 index 000000000..384c729de --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/table_create.go @@ -0,0 +1,248 @@ +package orm + +import ( + "sort" + "strconv" + + "github.com/go-pg/pg/v10/types" +) + +type CreateTableOptions struct { + Varchar int // replaces PostgreSQL data type `text` with `varchar(n)` + Temp bool + IfNotExists bool + + // FKConstraints causes CreateTable to create foreign key constraints + // for has one relations. ON DELETE hook can be added using tag + // `pg:"on_delete:RESTRICT"` on foreign key field. ON UPDATE hook can be added using tag + // `pg:"on_update:CASCADE"` + FKConstraints bool +} + +type CreateTableQuery struct { + q *Query + opt *CreateTableOptions +} + +var ( + _ QueryAppender = (*CreateTableQuery)(nil) + _ QueryCommand = (*CreateTableQuery)(nil) +) + +func NewCreateTableQuery(q *Query, opt *CreateTableOptions) *CreateTableQuery { + return &CreateTableQuery{ + q: q, + opt: opt, + } +} + +func (q *CreateTableQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *CreateTableQuery) Operation() QueryOp { + return CreateTableOp +} + +func (q *CreateTableQuery) Clone() QueryCommand { + return &CreateTableQuery{ + q: q.q.Clone(), + opt: q.opt, + } +} + +func (q *CreateTableQuery) Query() *Query { + return q.q +} + +func (q *CreateTableQuery) AppendTemplate(b []byte) ([]byte, error) { + return q.AppendQuery(dummyFormatter{}, b) +} + +func (q *CreateTableQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + if q.q.tableModel == nil { + return nil, errModelNil + } + + table := q.q.tableModel.Table() + + b = append(b, "CREATE "...) + if q.opt != nil && q.opt.Temp { + b = append(b, "TEMP "...) + } + b = append(b, "TABLE "...) + if q.opt != nil && q.opt.IfNotExists { + b = append(b, "IF NOT EXISTS "...) + } + b, err = q.q.appendFirstTable(fmter, b) + if err != nil { + return nil, err + } + b = append(b, " ("...) + + for i, field := range table.Fields { + if i > 0 { + b = append(b, ", "...) + } + + b = append(b, field.Column...) + b = append(b, " "...) + b = q.appendSQLType(b, field) + if field.hasFlag(NotNullFlag) { + b = append(b, " NOT NULL"...) + } + if field.hasFlag(UniqueFlag) { + b = append(b, " UNIQUE"...) + } + if field.Default != "" { + b = append(b, " DEFAULT "...) + b = append(b, field.Default...) + } + } + + b = appendPKConstraint(b, table.PKs) + b = appendUniqueConstraints(b, table) + + if q.opt != nil && q.opt.FKConstraints { + for _, rel := range table.Relations { + b = q.appendFKConstraint(fmter, b, rel) + } + } + + b = append(b, ")"...) + + if table.PartitionBy != "" { + b = append(b, " PARTITION BY "...) + b = append(b, table.PartitionBy...) + } + + if table.Tablespace != "" { + b = q.appendTablespace(b, table.Tablespace) + } + + return b, q.q.stickyErr +} + +func (q *CreateTableQuery) appendSQLType(b []byte, field *Field) []byte { + if field.UserSQLType != "" { + return append(b, field.UserSQLType...) + } + if q.opt != nil && q.opt.Varchar > 0 && + field.SQLType == "text" { + b = append(b, "varchar("...) + b = strconv.AppendInt(b, int64(q.opt.Varchar), 10) + b = append(b, ")"...) + return b + } + if field.hasFlag(PrimaryKeyFlag) { + return append(b, pkSQLType(field.SQLType)...) + } + return append(b, field.SQLType...) +} + +func pkSQLType(s string) string { + switch s { + case pgTypeSmallint: + return pgTypeSmallserial + case pgTypeInteger: + return pgTypeSerial + case pgTypeBigint: + return pgTypeBigserial + } + return s +} + +func appendPKConstraint(b []byte, pks []*Field) []byte { + if len(pks) == 0 { + return b + } + + b = append(b, ", PRIMARY KEY ("...) + b = appendColumns(b, "", pks) + b = append(b, ")"...) + return b +} + +func appendUniqueConstraints(b []byte, table *Table) []byte { + keys := make([]string, 0, len(table.Unique)) + for key := range table.Unique { + keys = append(keys, key) + } + sort.Strings(keys) + + for _, key := range keys { + b = appendUnique(b, table.Unique[key]) + } + + return b +} + +func appendUnique(b []byte, fields []*Field) []byte { + b = append(b, ", UNIQUE ("...) + b = appendColumns(b, "", fields) + b = append(b, ")"...) + return b +} + +func (q *CreateTableQuery) appendFKConstraint(fmter QueryFormatter, b []byte, rel *Relation) []byte { + if rel.Type != HasOneRelation { + return b + } + + b = append(b, ", FOREIGN KEY ("...) + b = appendColumns(b, "", rel.BaseFKs) + b = append(b, ")"...) + + b = append(b, " REFERENCES "...) + b = fmter.FormatQuery(b, string(rel.JoinTable.SQLName)) + b = append(b, " ("...) + b = appendColumns(b, "", rel.JoinFKs) + b = append(b, ")"...) + + if s := onDelete(rel.BaseFKs); s != "" { + b = append(b, " ON DELETE "...) + b = append(b, s...) + } + + if s := onUpdate(rel.BaseFKs); s != "" { + b = append(b, " ON UPDATE "...) + b = append(b, s...) + } + + return b +} + +func (q *CreateTableQuery) appendTablespace(b []byte, tableSpace types.Safe) []byte { + b = append(b, " TABLESPACE "...) + b = append(b, tableSpace...) + return b +} + +func onDelete(fks []*Field) string { + var onDelete string + for _, f := range fks { + if f.OnDelete != "" { + onDelete = f.OnDelete + break + } + } + return onDelete +} + +func onUpdate(fks []*Field) string { + var onUpdate string + for _, f := range fks { + if f.OnUpdate != "" { + onUpdate = f.OnUpdate + break + } + } + return onUpdate +} diff --git a/vendor/github.com/go-pg/pg/v10/orm/table_drop.go b/vendor/github.com/go-pg/pg/v10/orm/table_drop.go new file mode 100644 index 000000000..599ac3952 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/table_drop.go @@ -0,0 +1,73 @@ +package orm + +type DropTableOptions struct { + IfExists bool + Cascade bool +} + +type DropTableQuery struct { + q *Query + opt *DropTableOptions +} + +var ( + _ QueryAppender = (*DropTableQuery)(nil) + _ QueryCommand = (*DropTableQuery)(nil) +) + +func NewDropTableQuery(q *Query, opt *DropTableOptions) *DropTableQuery { + return &DropTableQuery{ + q: q, + opt: opt, + } +} + +func (q *DropTableQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *DropTableQuery) Operation() QueryOp { + return DropTableOp +} + +func (q *DropTableQuery) Clone() QueryCommand { + return &DropTableQuery{ + q: q.q.Clone(), + opt: q.opt, + } +} + +func (q *DropTableQuery) Query() *Query { + return q.q +} + +func (q *DropTableQuery) AppendTemplate(b []byte) ([]byte, error) { + return q.AppendQuery(dummyFormatter{}, b) +} + +func (q *DropTableQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + if q.q.tableModel == nil { + return nil, errModelNil + } + + b = append(b, "DROP TABLE "...) + if q.opt != nil && q.opt.IfExists { + b = append(b, "IF EXISTS "...) + } + b, err = q.q.appendFirstTable(fmter, b) + if err != nil { + return nil, err + } + if q.opt != nil && q.opt.Cascade { + b = append(b, " CASCADE"...) + } + + return b, q.q.stickyErr +} diff --git a/vendor/github.com/go-pg/pg/orm/table_params.go b/vendor/github.com/go-pg/pg/v10/orm/table_params.go similarity index 81% rename from vendor/github.com/go-pg/pg/orm/table_params.go rename to vendor/github.com/go-pg/pg/v10/orm/table_params.go index db3437a50..46d8e064a 100644 --- a/vendor/github.com/go-pg/pg/orm/table_params.go +++ b/vendor/github.com/go-pg/pg/v10/orm/table_params.go @@ -24,6 +24,6 @@ func newTableParams(strct interface{}) (*tableParams, bool) { }, true } -func (m tableParams) AppendParam(b []byte, f QueryFormatter, name string) ([]byte, bool) { +func (m *tableParams) AppendParam(fmter QueryFormatter, b []byte, name string) ([]byte, bool) { return m.table.AppendParam(b, m.strct, name) } diff --git a/vendor/github.com/go-pg/pg/orm/tables.go b/vendor/github.com/go-pg/pg/v10/orm/tables.go similarity index 51% rename from vendor/github.com/go-pg/pg/orm/tables.go rename to vendor/github.com/go-pg/pg/v10/orm/tables.go index 0a01b030c..fa937a54e 100644 --- a/vendor/github.com/go-pg/pg/orm/tables.go +++ b/vendor/github.com/go-pg/pg/v10/orm/tables.go @@ -4,13 +4,41 @@ import ( "fmt" "reflect" "sync" + + "github.com/go-pg/pg/v10/types" ) var _tables = newTables() type tableInProgress struct { table *Table - wg sync.WaitGroup + + init1Once sync.Once + init2Once sync.Once +} + +func newTableInProgress(table *Table) *tableInProgress { + return &tableInProgress{ + table: table, + } +} + +func (inp *tableInProgress) init1() bool { + var inited bool + inp.init1Once.Do(func() { + inp.table.init1() + inited = true + }) + return inited +} + +func (inp *tableInProgress) init2() bool { + var inited bool + inp.init2Once.Do(func() { + inp.table.init2() + inited = true + }) + return inited } // GetTable returns a Table for a struct type. @@ -26,15 +54,15 @@ func RegisterTable(strct interface{}) { } type tables struct { + tables sync.Map + mu sync.RWMutex inProgress map[reflect.Type]*tableInProgress - tables map[reflect.Type]*Table } func newTables() *tables { return &tables{ inProgress: make(map[reflect.Type]*tableInProgress), - tables: make(map[reflect.Type]*Table), } } @@ -51,46 +79,42 @@ func (t *tables) get(typ reflect.Type, allowInProgress bool) *Table { panic(fmt.Errorf("got %s, wanted %s", typ.Kind(), reflect.Struct)) } - t.mu.RLock() - table, ok := t.tables[typ] - t.mu.RUnlock() - if ok { - return table + if v, ok := t.tables.Load(typ); ok { + return v.(*Table) } t.mu.Lock() - table, ok = t.tables[typ] - if ok { + if v, ok := t.tables.Load(typ); ok { t.mu.Unlock() - return table + return v.(*Table) } - inProgress := t.inProgress[typ] - if inProgress != nil { - t.mu.Unlock() - if !allowInProgress { - inProgress.wg.Wait() - } - return inProgress.table - } + var table *Table - table = newTable(typ) - inProgress = &tableInProgress{ - table: table, + inProgress := t.inProgress[typ] + if inProgress == nil { + table = newTable(typ) + inProgress = newTableInProgress(table) + t.inProgress[typ] = inProgress + } else { + table = inProgress.table } - inProgress.wg.Add(1) - t.inProgress[typ] = inProgress t.mu.Unlock() - table.init() - inProgress.wg.Done() - t.mu.Lock() - delete(t.inProgress, typ) - t.tables[typ] = table + inProgress.init1() + if allowInProgress { + return table + } + + if inProgress.init2() { + t.mu.Lock() + delete(t.inProgress, typ) + t.tables.Store(typ, table) + t.mu.Unlock() + } - t.mu.Unlock() return table } @@ -98,15 +122,15 @@ func (t *tables) Get(typ reflect.Type) *Table { return t.get(typ, false) } -func (t *tables) getByName(name string) *Table { - t.mu.RLock() - defer t.mu.RUnlock() - - for _, t := range t.tables { - if string(t.Name) == name || t.ModelName == name { - return t +func (t *tables) getByName(name types.Safe) *Table { + var found *Table + t.tables.Range(func(key, value interface{}) bool { + t := value.(*Table) + if t.SQLName == name { + found = t + return false } - } - - return nil + return true + }) + return found } diff --git a/vendor/github.com/go-pg/pg/v10/orm/types.go b/vendor/github.com/go-pg/pg/v10/orm/types.go new file mode 100644 index 000000000..c8e9ec375 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/types.go @@ -0,0 +1,48 @@ +package orm + +//nolint +const ( + // Date / Time + pgTypeTimestamp = "timestamp" // Timestamp without a time zone + pgTypeTimestampTz = "timestamptz" // Timestamp with a time zone + pgTypeDate = "date" // Date + pgTypeTime = "time" // Time without a time zone + pgTypeTimeTz = "time with time zone" // Time with a time zone + pgTypeInterval = "interval" // Time Interval + + // Network Addresses + pgTypeInet = "inet" // IPv4 or IPv6 hosts and networks + pgTypeCidr = "cidr" // IPv4 or IPv6 networks + pgTypeMacaddr = "macaddr" // MAC addresses + + // Boolean + pgTypeBoolean = "boolean" + + // Numeric Types + + // Floating Point Types + pgTypeReal = "real" // 4 byte floating point (6 digit precision) + pgTypeDoublePrecision = "double precision" // 8 byte floating point (15 digit precision) + + // Integer Types + pgTypeSmallint = "smallint" // 2 byte integer + pgTypeInteger = "integer" // 4 byte integer + pgTypeBigint = "bigint" // 8 byte integer + + // Serial Types + pgTypeSmallserial = "smallserial" // 2 byte autoincrementing integer + pgTypeSerial = "serial" // 4 byte autoincrementing integer + pgTypeBigserial = "bigserial" // 8 byte autoincrementing integer + + // Character Types + pgTypeVarchar = "varchar" // variable length string with limit + pgTypeChar = "char" // fixed length string (blank padded) + pgTypeText = "text" // variable length string without limit + + // JSON Types + pgTypeJSON = "json" // text representation of json data + pgTypeJSONB = "jsonb" // binary representation of json data + + // Binary Data Types + pgTypeBytea = "bytea" // binary string +) diff --git a/vendor/github.com/go-pg/pg/v10/orm/update.go b/vendor/github.com/go-pg/pg/v10/orm/update.go new file mode 100644 index 000000000..ce6396fd3 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/orm/update.go @@ -0,0 +1,378 @@ +package orm + +import ( + "fmt" + "reflect" + "sort" + + "github.com/go-pg/pg/v10/types" +) + +type UpdateQuery struct { + q *Query + omitZero bool + placeholder bool +} + +var ( + _ QueryAppender = (*UpdateQuery)(nil) + _ QueryCommand = (*UpdateQuery)(nil) +) + +func NewUpdateQuery(q *Query, omitZero bool) *UpdateQuery { + return &UpdateQuery{ + q: q, + omitZero: omitZero, + } +} + +func (q *UpdateQuery) String() string { + b, err := q.AppendQuery(defaultFmter, nil) + if err != nil { + panic(err) + } + return string(b) +} + +func (q *UpdateQuery) Operation() QueryOp { + return UpdateOp +} + +func (q *UpdateQuery) Clone() QueryCommand { + return &UpdateQuery{ + q: q.q.Clone(), + omitZero: q.omitZero, + placeholder: q.placeholder, + } +} + +func (q *UpdateQuery) Query() *Query { + return q.q +} + +func (q *UpdateQuery) AppendTemplate(b []byte) ([]byte, error) { + cp := q.Clone().(*UpdateQuery) + cp.placeholder = true + return cp.AppendQuery(dummyFormatter{}, b) +} + +func (q *UpdateQuery) AppendQuery(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if q.q.stickyErr != nil { + return nil, q.q.stickyErr + } + + if len(q.q.with) > 0 { + b, err = q.q.appendWith(fmter, b) + if err != nil { + return nil, err + } + } + + b = append(b, "UPDATE "...) + + b, err = q.q.appendFirstTableWithAlias(fmter, b) + if err != nil { + return nil, err + } + + b, err = q.mustAppendSet(fmter, b) + if err != nil { + return nil, err + } + + isSliceModelWithData := q.q.isSliceModelWithData() + if isSliceModelWithData || q.q.hasMultiTables() { + b = append(b, " FROM "...) + b, err = q.q.appendOtherTables(fmter, b) + if err != nil { + return nil, err + } + + if isSliceModelWithData { + b, err = q.appendSliceModelData(fmter, b) + if err != nil { + return nil, err + } + } + } + + b, err = q.mustAppendWhere(fmter, b, isSliceModelWithData) + if err != nil { + return nil, err + } + + if len(q.q.returning) > 0 { + b, err = q.q.appendReturning(fmter, b) + if err != nil { + return nil, err + } + } + + return b, q.q.stickyErr +} + +func (q *UpdateQuery) mustAppendWhere( + fmter QueryFormatter, b []byte, isSliceModelWithData bool, +) (_ []byte, err error) { + b = append(b, " WHERE "...) + + if !isSliceModelWithData { + return q.q.mustAppendWhere(fmter, b) + } + + if len(q.q.where) > 0 { + return q.q.appendWhere(fmter, b) + } + + table := q.q.tableModel.Table() + err = table.checkPKs() + if err != nil { + return nil, err + } + + b = appendWhereColumnAndColumn(b, table.Alias, table.PKs) + return b, nil +} + +func (q *UpdateQuery) mustAppendSet(fmter QueryFormatter, b []byte) (_ []byte, err error) { + if len(q.q.set) > 0 { + return q.q.appendSet(fmter, b) + } + + b = append(b, " SET "...) + + if m, ok := q.q.model.(*mapModel); ok { + return q.appendMapSet(b, m.m), nil + } + + if !q.q.hasTableModel() { + return nil, errModelNil + } + + value := q.q.tableModel.Value() + if value.Kind() == reflect.Struct { + b, err = q.appendSetStruct(fmter, b, value) + } else { + if value.Len() > 0 { + b, err = q.appendSetSlice(b) + } else { + err = fmt.Errorf("pg: can't bulk-update empty slice %s", value.Type()) + } + } + if err != nil { + return nil, err + } + + return b, nil +} + +func (q *UpdateQuery) appendMapSet(b []byte, m map[string]interface{}) []byte { + keys := make([]string, 0, len(m)) + + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + for i, k := range keys { + if i > 0 { + b = append(b, ", "...) + } + + b = types.AppendIdent(b, k, 1) + b = append(b, " = "...) + if q.placeholder { + b = append(b, '?') + } else { + b = types.Append(b, m[k], 1) + } + } + + return b +} + +func (q *UpdateQuery) appendSetStruct(fmter QueryFormatter, b []byte, strct reflect.Value) ([]byte, error) { + fields, err := q.q.getFields() + if err != nil { + return nil, err + } + + if len(fields) == 0 { + fields = q.q.tableModel.Table().DataFields + } + + pos := len(b) + for _, f := range fields { + if q.omitZero && f.NullZero() && f.HasZeroValue(strct) { + continue + } + + if len(b) != pos { + b = append(b, ", "...) + pos = len(b) + } + + b = append(b, f.Column...) + b = append(b, " = "...) + + if q.placeholder { + b = append(b, '?') + continue + } + + app, ok := q.q.modelValues[f.SQLName] + if ok { + b, err = app.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } else { + b = f.AppendValue(b, strct, 1) + } + } + + for i, v := range q.q.extraValues { + if i > 0 || len(fields) > 0 { + b = append(b, ", "...) + } + + b = append(b, v.column...) + b = append(b, " = "...) + + b, err = v.value.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + } + + return b, nil +} + +func (q *UpdateQuery) appendSetSlice(b []byte) ([]byte, error) { + fields, err := q.q.getFields() + if err != nil { + return nil, err + } + + if len(fields) == 0 { + fields = q.q.tableModel.Table().DataFields + } + + var table *Table + if q.omitZero { + table = q.q.tableModel.Table() + } + + for i, f := range fields { + if i > 0 { + b = append(b, ", "...) + } + + b = append(b, f.Column...) + b = append(b, " = "...) + if q.omitZero && table != nil { + b = append(b, "COALESCE("...) + } + b = append(b, "_data."...) + b = append(b, f.Column...) + if q.omitZero && table != nil { + b = append(b, ", "...) + if table.Alias != table.SQLName { + b = append(b, table.Alias...) + b = append(b, '.') + } + b = append(b, f.Column...) + b = append(b, ")"...) + } + } + + return b, nil +} + +func (q *UpdateQuery) appendSliceModelData(fmter QueryFormatter, b []byte) ([]byte, error) { + columns, err := q.q.getDataFields() + if err != nil { + return nil, err + } + + if len(columns) > 0 { + columns = append(columns, q.q.tableModel.Table().PKs...) + } else { + columns = q.q.tableModel.Table().Fields + } + + return q.appendSliceValues(fmter, b, columns, q.q.tableModel.Value()) +} + +func (q *UpdateQuery) appendSliceValues( + fmter QueryFormatter, b []byte, fields []*Field, slice reflect.Value, +) (_ []byte, err error) { + b = append(b, "(VALUES ("...) + + if q.placeholder { + b, err = q.appendValues(fmter, b, fields, reflect.Value{}) + if err != nil { + return nil, err + } + } else { + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + if i > 0 { + b = append(b, "), ("...) + } + b, err = q.appendValues(fmter, b, fields, slice.Index(i)) + if err != nil { + return nil, err + } + } + } + + b = append(b, ")) AS _data("...) + b = appendColumns(b, "", fields) + b = append(b, ")"...) + + return b, nil +} + +func (q *UpdateQuery) appendValues( + fmter QueryFormatter, b []byte, fields []*Field, strct reflect.Value, +) (_ []byte, err error) { + for i, f := range fields { + if i > 0 { + b = append(b, ", "...) + } + + app, ok := q.q.modelValues[f.SQLName] + if ok { + b, err = app.AppendQuery(fmter, b) + if err != nil { + return nil, err + } + continue + } + + if q.placeholder { + b = append(b, '?') + } else { + b = f.AppendValue(b, indirect(strct), 1) + } + + b = append(b, "::"...) + b = append(b, f.SQLType...) + } + return b, nil +} + +func appendWhereColumnAndColumn(b []byte, alias types.Safe, fields []*Field) []byte { + for i, f := range fields { + if i > 0 { + b = append(b, " AND "...) + } + b = append(b, alias...) + b = append(b, '.') + b = append(b, f.Column...) + b = append(b, " = _data."...) + b = append(b, f.Column...) + } + return b +} diff --git a/vendor/github.com/go-pg/pg/orm/util.go b/vendor/github.com/go-pg/pg/v10/orm/util.go similarity index 61% rename from vendor/github.com/go-pg/pg/orm/util.go rename to vendor/github.com/go-pg/pg/v10/orm/util.go index 73b1a7f76..b7963ba0b 100644 --- a/vendor/github.com/go-pg/pg/orm/util.go +++ b/vendor/github.com/go-pg/pg/v10/orm/util.go @@ -3,7 +3,7 @@ package orm import ( "reflect" - "github.com/go-pg/pg/types" + "github.com/go-pg/pg/v10/types" ) func indirect(v reflect.Value) reflect.Value { @@ -28,9 +28,8 @@ func sliceElemType(v reflect.Value) reflect.Type { elemType := v.Type().Elem() if elemType.Kind() == reflect.Interface && v.Len() > 0 { return indirect(v.Index(0).Elem()).Type() - } else { - return indirectType(elemType) } + return indirectType(elemType) } func typeByIndex(t reflect.Type, index []int) reflect.Type { @@ -46,17 +45,40 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type { return indirectType(t) } -func fieldByIndex(v reflect.Value, index []int) reflect.Value { - for i, x := range index { +func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, ok bool) { + if len(index) == 1 { + return v.Field(index[0]), true + } + + for i, idx := range index { + if i > 0 { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return v, false + } + v = v.Elem() + } + } + v = v.Field(idx) + } + return v, true +} + +func fieldByIndexAlloc(v reflect.Value, index []int) reflect.Value { + if len(index) == 1 { + return v.Field(index[0]) + } + + for i, idx := range index { if i > 0 { - v = indirectNew(v) + v = indirectNil(v) } - v = v.Field(x) + v = v.Field(idx) } return v } -func indirectNew(v reflect.Value) reflect.Value { +func indirectNil(v reflect.Value) reflect.Value { if v.Kind() == reflect.Ptr { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) @@ -70,7 +92,8 @@ func walk(v reflect.Value, index []int, fn func(reflect.Value)) { v = reflect.Indirect(v) switch v.Kind() { case reflect.Slice: - for i := 0; i < v.Len(); i++ { + sliceLen := v.Len() + for i := 0; i < sliceLen; i++ { visitField(v.Index(i), index, fn) } default: @@ -91,17 +114,18 @@ func visitField(v reflect.Value, index []int, fn func(reflect.Value)) { } } -func dstValues(model tableModel, fields []*Field) map[string][]reflect.Value { - mp := make(map[string][]reflect.Value) +func dstValues(model TableModel, fields []*Field) map[string][]reflect.Value { + fieldIndex := model.Relation().Field.Index + m := make(map[string][]reflect.Value) var id []byte walk(model.Root(), model.ParentIndex(), func(v reflect.Value) { - id = modelId(id[:0], v, fields) - mp[string(id)] = append(mp[string(id)], v.FieldByIndex(model.Relation().Field.Index)) + id = modelID(id[:0], v, fields) + m[string(id)] = append(m[string(id)], v.FieldByIndex(fieldIndex)) }) - return mp + return m } -func modelId(b []byte, v reflect.Value, fields []*Field) []byte { +func modelID(b []byte, v reflect.Value, fields []*Field) []byte { for i, f := range fields { if i > 0 { b = append(b, ',') @@ -111,7 +135,7 @@ func modelId(b []byte, v reflect.Value, fields []*Field) []byte { return b } -func appendColumns(b []byte, table types.Q, fields []*Field) []byte { +func appendColumns(b []byte, table types.Safe, fields []*Field) []byte { for i, f := range fields { if i > 0 { b = append(b, ", "...) @@ -121,7 +145,7 @@ func appendColumns(b []byte, table types.Q, fields []*Field) []byte { b = append(b, table...) b = append(b, '.') } - b = types.AppendField(b, f.SQLName, 1) + b = append(b, f.Column...) } return b } diff --git a/vendor/github.com/go-pg/pg/v10/pg.go b/vendor/github.com/go-pg/pg/v10/pg.go new file mode 100644 index 000000000..923ef6bef --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/pg.go @@ -0,0 +1,274 @@ +package pg + +import ( + "context" + "io" + "strconv" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/orm" + "github.com/go-pg/pg/v10/types" +) + +// Discard is used with Query and QueryOne to discard rows. +var Discard orm.Discard + +// NullTime is a time.Time wrapper that marshals zero time as JSON null and +// PostgreSQL NULL. +type NullTime = types.NullTime + +// Scan returns ColumnScanner that copies the columns in the +// row into the values. +func Scan(values ...interface{}) orm.ColumnScanner { + return orm.Scan(values...) +} + +// Safe represents a safe SQL query. +type Safe = types.Safe + +// Ident represents a SQL identifier, e.g. table or column name. +type Ident = types.Ident + +// SafeQuery replaces any placeholders found in the query. +func SafeQuery(query string, params ...interface{}) *orm.SafeQueryAppender { + return orm.SafeQuery(query, params...) +} + +// In accepts a slice and returns a wrapper that can be used with PostgreSQL +// IN operator: +// +// Where("id IN (?)", pg.In([]int{1, 2, 3, 4})) +// +// produces +// +// WHERE id IN (1, 2, 3, 4) +func In(slice interface{}) types.ValueAppender { + return types.In(slice) +} + +// InMulti accepts multiple values and returns a wrapper that can be used +// with PostgreSQL IN operator: +// +// Where("(id1, id2) IN (?)", pg.InMulti([]int{1, 2}, []int{3, 4})) +// +// produces +// +// WHERE (id1, id2) IN ((1, 2), (3, 4)) +func InMulti(values ...interface{}) types.ValueAppender { + return types.InMulti(values...) +} + +// Array accepts a slice and returns a wrapper for working with PostgreSQL +// array data type. +// +// For struct fields you can use array tag: +// +// Emails []string `pg:",array"` +func Array(v interface{}) *types.Array { + return types.NewArray(v) +} + +// Hstore accepts a map and returns a wrapper for working with hstore data type. +// Supported map types are: +// - map[string]string +// +// For struct fields you can use hstore tag: +// +// Attrs map[string]string `pg:",hstore"` +func Hstore(v interface{}) *types.Hstore { + return types.NewHstore(v) +} + +// SetLogger sets the logger to the given one. +func SetLogger(logger internal.Logging) { + internal.Logger = logger +} + +//------------------------------------------------------------------------------ + +type Query = orm.Query + +// Model returns a new query for the optional model. +func Model(model ...interface{}) *Query { + return orm.NewQuery(nil, model...) +} + +// ModelContext returns a new query for the optional model with a context. +func ModelContext(c context.Context, model ...interface{}) *Query { + return orm.NewQueryContext(c, nil, model...) +} + +// DBI is a DB interface implemented by *DB and *Tx. +type DBI interface { + Model(model ...interface{}) *Query + ModelContext(c context.Context, model ...interface{}) *Query + + Exec(query interface{}, params ...interface{}) (Result, error) + ExecContext(c context.Context, query interface{}, params ...interface{}) (Result, error) + ExecOne(query interface{}, params ...interface{}) (Result, error) + ExecOneContext(c context.Context, query interface{}, params ...interface{}) (Result, error) + Query(model, query interface{}, params ...interface{}) (Result, error) + QueryContext(c context.Context, model, query interface{}, params ...interface{}) (Result, error) + QueryOne(model, query interface{}, params ...interface{}) (Result, error) + QueryOneContext(c context.Context, model, query interface{}, params ...interface{}) (Result, error) + + Begin() (*Tx, error) + RunInTransaction(ctx context.Context, fn func(*Tx) error) error + + CopyFrom(r io.Reader, query interface{}, params ...interface{}) (Result, error) + CopyTo(w io.Writer, query interface{}, params ...interface{}) (Result, error) +} + +var ( + _ DBI = (*DB)(nil) + _ DBI = (*Tx)(nil) +) + +//------------------------------------------------------------------------------ + +// Strings is a type alias for a slice of strings. +type Strings []string + +var ( + _ orm.HooklessModel = (*Strings)(nil) + _ types.ValueAppender = (*Strings)(nil) +) + +// Init initializes the Strings slice. +func (strings *Strings) Init() error { + if s := *strings; len(s) > 0 { + *strings = s[:0] + } + return nil +} + +// NextColumnScanner ... +func (strings *Strings) NextColumnScanner() orm.ColumnScanner { + return strings +} + +// AddColumnScanner ... +func (Strings) AddColumnScanner(_ orm.ColumnScanner) error { + return nil +} + +// ScanColumn scans the columns and appends them to `strings`. +func (strings *Strings) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + b := make([]byte, n) + _, err := io.ReadFull(rd, b) + if err != nil { + return err + } + + *strings = append(*strings, internal.BytesToString(b)) + return nil +} + +// AppendValue appends the values from `strings` to the given byte slice. +func (strings Strings) AppendValue(dst []byte, quote int) ([]byte, error) { + if len(strings) == 0 { + return dst, nil + } + + for _, s := range strings { + dst = types.AppendString(dst, s, 1) + dst = append(dst, ',') + } + dst = dst[:len(dst)-1] + return dst, nil +} + +//------------------------------------------------------------------------------ + +// Ints is a type alias for a slice of int64 values. +type Ints []int64 + +var ( + _ orm.HooklessModel = (*Ints)(nil) + _ types.ValueAppender = (*Ints)(nil) +) + +// Init initializes the Int slice. +func (ints *Ints) Init() error { + if s := *ints; len(s) > 0 { + *ints = s[:0] + } + return nil +} + +// NewColumnScanner ... +func (ints *Ints) NextColumnScanner() orm.ColumnScanner { + return ints +} + +// AddColumnScanner ... +func (Ints) AddColumnScanner(_ orm.ColumnScanner) error { + return nil +} + +// ScanColumn scans the columns and appends them to `ints`. +func (ints *Ints) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + num, err := types.ScanInt64(rd, n) + if err != nil { + return err + } + + *ints = append(*ints, num) + return nil +} + +// AppendValue appends the values from `ints` to the given byte slice. +func (ints Ints) AppendValue(dst []byte, quote int) ([]byte, error) { + if len(ints) == 0 { + return dst, nil + } + + for _, v := range ints { + dst = strconv.AppendInt(dst, v, 10) + dst = append(dst, ',') + } + dst = dst[:len(dst)-1] + return dst, nil +} + +//------------------------------------------------------------------------------ + +// IntSet is a set of int64 values. +type IntSet map[int64]struct{} + +var _ orm.HooklessModel = (*IntSet)(nil) + +// Init initializes the IntSet. +func (set *IntSet) Init() error { + if len(*set) > 0 { + *set = make(map[int64]struct{}) + } + return nil +} + +// NextColumnScanner ... +func (set *IntSet) NextColumnScanner() orm.ColumnScanner { + return set +} + +// AddColumnScanner ... +func (IntSet) AddColumnScanner(_ orm.ColumnScanner) error { + return nil +} + +// ScanColumn scans the columns and appends them to `IntSet`. +func (set *IntSet) ScanColumn(col types.ColumnInfo, rd types.Reader, n int) error { + num, err := types.ScanInt64(rd, n) + if err != nil { + return err + } + + setVal := *set + if setVal == nil { + *set = make(IntSet) + setVal = *set + } + + setVal[num] = struct{}{} + return nil +} diff --git a/vendor/github.com/go-pg/pg/v10/pgjson/json.go b/vendor/github.com/go-pg/pg/v10/pgjson/json.go new file mode 100644 index 000000000..c401dc946 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/pgjson/json.go @@ -0,0 +1,26 @@ +package pgjson + +import ( + "encoding/json" + "io" +) + +var _ Provider = (*StdProvider)(nil) + +type StdProvider struct{} + +func (StdProvider) Marshal(v interface{}) ([]byte, error) { + return json.Marshal(v) +} + +func (StdProvider) Unmarshal(data []byte, v interface{}) error { + return json.Unmarshal(data, v) +} + +func (StdProvider) NewEncoder(w io.Writer) Encoder { + return json.NewEncoder(w) +} + +func (StdProvider) NewDecoder(r io.Reader) Decoder { + return json.NewDecoder(r) +} diff --git a/vendor/github.com/go-pg/pg/v10/pgjson/provider.go b/vendor/github.com/go-pg/pg/v10/pgjson/provider.go new file mode 100644 index 000000000..a4b663ce4 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/pgjson/provider.go @@ -0,0 +1,43 @@ +package pgjson + +import ( + "io" +) + +var provider Provider = StdProvider{} + +func SetProvider(p Provider) { + provider = p +} + +type Provider interface { + Marshal(v interface{}) ([]byte, error) + Unmarshal(data []byte, v interface{}) error + NewEncoder(w io.Writer) Encoder + NewDecoder(r io.Reader) Decoder +} + +type Decoder interface { + Decode(v interface{}) error + UseNumber() +} + +type Encoder interface { + Encode(v interface{}) error +} + +func Marshal(v interface{}) ([]byte, error) { + return provider.Marshal(v) +} + +func Unmarshal(data []byte, v interface{}) error { + return provider.Unmarshal(data, v) +} + +func NewEncoder(w io.Writer) Encoder { + return provider.NewEncoder(w) +} + +func NewDecoder(r io.Reader) Decoder { + return provider.NewDecoder(r) +} diff --git a/vendor/github.com/go-pg/pg/result.go b/vendor/github.com/go-pg/pg/v10/result.go similarity index 77% rename from vendor/github.com/go-pg/pg/result.go rename to vendor/github.com/go-pg/pg/v10/result.go index 3a61b3b9a..b8d8d9e45 100644 --- a/vendor/github.com/go-pg/pg/result.go +++ b/vendor/github.com/go-pg/pg/v10/result.go @@ -4,10 +4,13 @@ import ( "bytes" "strconv" - "github.com/go-pg/pg/internal" - "github.com/go-pg/pg/orm" + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/orm" ) +// Result summarizes an executed SQL command. +type Result = orm.Result + // A result summarizes an executed SQL command. type result struct { model orm.Model @@ -16,8 +19,9 @@ type result struct { returned int } -var _ orm.Result = (*result)(nil) +var _ Result = (*result)(nil) +//nolint func (res *result) parse(b []byte) error { res.affected = -1 diff --git a/vendor/github.com/go-pg/pg/v10/stmt.go b/vendor/github.com/go-pg/pg/v10/stmt.go new file mode 100644 index 000000000..528788379 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/stmt.go @@ -0,0 +1,282 @@ +package pg + +import ( + "context" + "errors" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/orm" + "github.com/go-pg/pg/v10/types" +) + +var errStmtClosed = errors.New("pg: statement is closed") + +// Stmt is a prepared statement. Stmt is safe for concurrent use by +// multiple goroutines. +type Stmt struct { + db *baseDB + stickyErr error + + q string + name string + columns []types.ColumnInfo +} + +func prepareStmt(db *baseDB, q string) (*Stmt, error) { + stmt := &Stmt{ + db: db, + + q: q, + } + + err := stmt.prepare(context.TODO(), q) + if err != nil { + _ = stmt.Close() + return nil, err + } + return stmt, nil +} + +func (stmt *Stmt) prepare(ctx context.Context, q string) error { + var lastErr error + for attempt := 0; attempt <= stmt.db.opt.MaxRetries; attempt++ { + if attempt > 0 { + if err := internal.Sleep(ctx, stmt.db.retryBackoff(attempt-1)); err != nil { + return err + } + + err := stmt.db.pool.(*pool.StickyConnPool).Reset(ctx) + if err != nil { + return err + } + } + + lastErr = stmt.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { + var err error + stmt.name, stmt.columns, err = stmt.db.prepare(ctx, cn, q) + return err + }) + if !stmt.db.shouldRetry(lastErr) { + break + } + } + return lastErr +} + +func (stmt *Stmt) withConn(c context.Context, fn func(context.Context, *pool.Conn) error) error { + if stmt.stickyErr != nil { + return stmt.stickyErr + } + err := stmt.db.withConn(c, fn) + if err == pool.ErrClosed { + return errStmtClosed + } + return err +} + +// Exec executes a prepared statement with the given parameters. +func (stmt *Stmt) Exec(params ...interface{}) (Result, error) { + return stmt.exec(context.TODO(), params...) +} + +// ExecContext executes a prepared statement with the given parameters. +func (stmt *Stmt) ExecContext(c context.Context, params ...interface{}) (Result, error) { + return stmt.exec(c, params...) +} + +func (stmt *Stmt) exec(ctx context.Context, params ...interface{}) (Result, error) { + ctx, evt, err := stmt.db.beforeQuery(ctx, stmt.db.db, nil, stmt.q, params, nil) + if err != nil { + return nil, err + } + + var res Result + var lastErr error + for attempt := 0; attempt <= stmt.db.opt.MaxRetries; attempt++ { + if attempt > 0 { + lastErr = internal.Sleep(ctx, stmt.db.retryBackoff(attempt-1)) + if lastErr != nil { + break + } + } + + lastErr = stmt.withConn(ctx, func(c context.Context, cn *pool.Conn) error { + res, err = stmt.extQuery(ctx, cn, stmt.name, params...) + return err + }) + if !stmt.db.shouldRetry(lastErr) { + break + } + } + + if err := stmt.db.afterQuery(ctx, evt, res, lastErr); err != nil { + return nil, err + } + return res, lastErr +} + +// ExecOne acts like Exec, but query must affect only one row. It +// returns ErrNoRows error when query returns zero rows or +// ErrMultiRows when query returns multiple rows. +func (stmt *Stmt) ExecOne(params ...interface{}) (Result, error) { + return stmt.execOne(context.Background(), params...) +} + +// ExecOneContext acts like ExecOne but additionally receives a context. +func (stmt *Stmt) ExecOneContext(c context.Context, params ...interface{}) (Result, error) { + return stmt.execOne(c, params...) +} + +func (stmt *Stmt) execOne(c context.Context, params ...interface{}) (Result, error) { + res, err := stmt.ExecContext(c, params...) + if err != nil { + return nil, err + } + + if err := internal.AssertOneRow(res.RowsAffected()); err != nil { + return nil, err + } + return res, nil +} + +// Query executes a prepared query statement with the given parameters. +func (stmt *Stmt) Query(model interface{}, params ...interface{}) (Result, error) { + return stmt.query(context.Background(), model, params...) +} + +// QueryContext acts like Query but additionally receives a context. +func (stmt *Stmt) QueryContext(c context.Context, model interface{}, params ...interface{}) (Result, error) { + return stmt.query(c, model, params...) +} + +func (stmt *Stmt) query(ctx context.Context, model interface{}, params ...interface{}) (Result, error) { + ctx, evt, err := stmt.db.beforeQuery(ctx, stmt.db.db, model, stmt.q, params, nil) + if err != nil { + return nil, err + } + + var res Result + var lastErr error + for attempt := 0; attempt <= stmt.db.opt.MaxRetries; attempt++ { + if attempt > 0 { + lastErr = internal.Sleep(ctx, stmt.db.retryBackoff(attempt-1)) + if lastErr != nil { + break + } + } + + lastErr = stmt.withConn(ctx, func(c context.Context, cn *pool.Conn) error { + res, err = stmt.extQueryData(ctx, cn, stmt.name, model, stmt.columns, params...) + return err + }) + if !stmt.db.shouldRetry(lastErr) { + break + } + } + + if err := stmt.db.afterQuery(ctx, evt, res, lastErr); err != nil { + return nil, err + } + return res, lastErr +} + +// QueryOne acts like Query, but query must return only one row. It +// returns ErrNoRows error when query returns zero rows or +// ErrMultiRows when query returns multiple rows. +func (stmt *Stmt) QueryOne(model interface{}, params ...interface{}) (Result, error) { + return stmt.queryOne(context.Background(), model, params...) +} + +// QueryOneContext acts like QueryOne but additionally receives a context. +func (stmt *Stmt) QueryOneContext(c context.Context, model interface{}, params ...interface{}) (Result, error) { + return stmt.queryOne(c, model, params...) +} + +func (stmt *Stmt) queryOne(c context.Context, model interface{}, params ...interface{}) (Result, error) { + mod, err := orm.NewModel(model) + if err != nil { + return nil, err + } + + res, err := stmt.QueryContext(c, mod, params...) + if err != nil { + return nil, err + } + + if err := internal.AssertOneRow(res.RowsAffected()); err != nil { + return nil, err + } + return res, nil +} + +// Close closes the statement. +func (stmt *Stmt) Close() error { + var firstErr error + + if stmt.name != "" { + firstErr = stmt.closeStmt() + } + + err := stmt.db.Close() + if err != nil && firstErr == nil { + firstErr = err + } + + return firstErr +} + +func (stmt *Stmt) extQuery( + c context.Context, cn *pool.Conn, name string, params ...interface{}, +) (Result, error) { + err := cn.WithWriter(c, stmt.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + return writeBindExecuteMsg(wb, name, params...) + }) + if err != nil { + return nil, err + } + + var res Result + err = cn.WithReader(c, stmt.db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + res, err = readExtQuery(rd) + return err + }) + if err != nil { + return nil, err + } + + return res, nil +} + +func (stmt *Stmt) extQueryData( + c context.Context, + cn *pool.Conn, + name string, + model interface{}, + columns []types.ColumnInfo, + params ...interface{}, +) (Result, error) { + err := cn.WithWriter(c, stmt.db.opt.WriteTimeout, func(wb *pool.WriteBuffer) error { + return writeBindExecuteMsg(wb, name, params...) + }) + if err != nil { + return nil, err + } + + var res *result + err = cn.WithReader(c, stmt.db.opt.ReadTimeout, func(rd *pool.ReaderContext) error { + res, err = readExtQueryData(c, rd, model, columns) + return err + }) + if err != nil { + return nil, err + } + + return res, nil +} + +func (stmt *Stmt) closeStmt() error { + return stmt.withConn(context.TODO(), func(c context.Context, cn *pool.Conn) error { + return stmt.db.closeStmt(c, cn, stmt.name) + }) +} diff --git a/vendor/github.com/go-pg/pg/v10/tx.go b/vendor/github.com/go-pg/pg/v10/tx.go new file mode 100644 index 000000000..db444ff65 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/tx.go @@ -0,0 +1,388 @@ +package pg + +import ( + "context" + "errors" + "io" + "sync" + "sync/atomic" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/orm" +) + +// ErrTxDone is returned by any operation that is performed on a transaction +// that has already been committed or rolled back. +var ErrTxDone = errors.New("pg: transaction has already been committed or rolled back") + +// Tx is an in-progress database transaction. It is safe for concurrent use +// by multiple goroutines. +// +// A transaction must end with a call to Commit or Rollback. +// +// After a call to Commit or Rollback, all operations on the transaction fail +// with ErrTxDone. +// +// The statements prepared for a transaction by calling the transaction's +// Prepare or Stmt methods are closed by the call to Commit or Rollback. +type Tx struct { + db *baseDB + ctx context.Context + + stmtsMu sync.Mutex + stmts []*Stmt + + _closed int32 +} + +var _ orm.DB = (*Tx)(nil) + +// Context returns the context.Context of the transaction. +func (tx *Tx) Context() context.Context { + return tx.ctx +} + +// Begin starts a transaction. Most callers should use RunInTransaction instead. +func (db *baseDB) Begin() (*Tx, error) { + return db.BeginContext(db.db.Context()) +} + +func (db *baseDB) BeginContext(ctx context.Context) (*Tx, error) { + tx := &Tx{ + db: db.withPool(pool.NewStickyConnPool(db.pool)), + ctx: ctx, + } + + err := tx.begin(ctx) + if err != nil { + tx.close() + return nil, err + } + + return tx, nil +} + +// RunInTransaction runs a function in a transaction. If function +// returns an error transaction is rolled back, otherwise transaction +// is committed. +func (db *baseDB) RunInTransaction(ctx context.Context, fn func(*Tx) error) error { + tx, err := db.BeginContext(ctx) + if err != nil { + return err + } + return tx.RunInTransaction(ctx, fn) +} + +// Begin returns current transaction. It does not start new transaction. +func (tx *Tx) Begin() (*Tx, error) { + return tx, nil +} + +// RunInTransaction runs a function in the transaction. If function +// returns an error transaction is rolled back, otherwise transaction +// is committed. +func (tx *Tx) RunInTransaction(ctx context.Context, fn func(*Tx) error) error { + defer func() { + if err := recover(); err != nil { + if err := tx.RollbackContext(ctx); err != nil { + internal.Logger.Printf(ctx, "tx.Rollback panicked: %s", err) + } + panic(err) + } + }() + + if err := fn(tx); err != nil { + if err := tx.RollbackContext(ctx); err != nil { + internal.Logger.Printf(ctx, "tx.Rollback failed: %s", err) + } + return err + } + return tx.CommitContext(ctx) +} + +func (tx *Tx) withConn(c context.Context, fn func(context.Context, *pool.Conn) error) error { + err := tx.db.withConn(c, fn) + if tx.closed() && err == pool.ErrClosed { + return ErrTxDone + } + return err +} + +// Stmt returns a transaction-specific prepared statement +// from an existing statement. +func (tx *Tx) Stmt(stmt *Stmt) *Stmt { + stmt, err := tx.Prepare(stmt.q) + if err != nil { + return &Stmt{stickyErr: err} + } + return stmt +} + +// Prepare creates a prepared statement for use within a transaction. +// +// The returned statement operates within the transaction and can no longer +// be used once the transaction has been committed or rolled back. +// +// To use an existing prepared statement on this transaction, see Tx.Stmt. +func (tx *Tx) Prepare(q string) (*Stmt, error) { + tx.stmtsMu.Lock() + defer tx.stmtsMu.Unlock() + + db := tx.db.withPool(pool.NewStickyConnPool(tx.db.pool)) + stmt, err := prepareStmt(db, q) + if err != nil { + return nil, err + } + tx.stmts = append(tx.stmts, stmt) + + return stmt, nil +} + +// Exec is an alias for DB.Exec. +func (tx *Tx) Exec(query interface{}, params ...interface{}) (Result, error) { + return tx.exec(tx.ctx, query, params...) +} + +// ExecContext acts like Exec but additionally receives a context. +func (tx *Tx) ExecContext(c context.Context, query interface{}, params ...interface{}) (Result, error) { + return tx.exec(c, query, params...) +} + +func (tx *Tx) exec(ctx context.Context, query interface{}, params ...interface{}) (Result, error) { + wb := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(wb) + + if err := writeQueryMsg(wb, tx.db.fmter, query, params...); err != nil { + return nil, err + } + + ctx, evt, err := tx.db.beforeQuery(ctx, tx, nil, query, params, wb.Query()) + if err != nil { + return nil, err + } + + var res Result + lastErr := tx.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { + res, err = tx.db.simpleQuery(ctx, cn, wb) + return err + }) + + if err := tx.db.afterQuery(ctx, evt, res, lastErr); err != nil { + return nil, err + } + return res, lastErr +} + +// ExecOne is an alias for DB.ExecOne. +func (tx *Tx) ExecOne(query interface{}, params ...interface{}) (Result, error) { + return tx.execOne(tx.ctx, query, params...) +} + +// ExecOneContext acts like ExecOne but additionally receives a context. +func (tx *Tx) ExecOneContext(c context.Context, query interface{}, params ...interface{}) (Result, error) { + return tx.execOne(c, query, params...) +} + +func (tx *Tx) execOne(c context.Context, query interface{}, params ...interface{}) (Result, error) { + res, err := tx.ExecContext(c, query, params...) + if err != nil { + return nil, err + } + + if err := internal.AssertOneRow(res.RowsAffected()); err != nil { + return nil, err + } + return res, nil +} + +// Query is an alias for DB.Query. +func (tx *Tx) Query(model interface{}, query interface{}, params ...interface{}) (Result, error) { + return tx.query(tx.ctx, model, query, params...) +} + +// QueryContext acts like Query but additionally receives a context. +func (tx *Tx) QueryContext( + c context.Context, + model interface{}, + query interface{}, + params ...interface{}, +) (Result, error) { + return tx.query(c, model, query, params...) +} + +func (tx *Tx) query( + ctx context.Context, + model interface{}, + query interface{}, + params ...interface{}, +) (Result, error) { + wb := pool.GetWriteBuffer() + defer pool.PutWriteBuffer(wb) + + if err := writeQueryMsg(wb, tx.db.fmter, query, params...); err != nil { + return nil, err + } + + ctx, evt, err := tx.db.beforeQuery(ctx, tx, model, query, params, wb.Query()) + if err != nil { + return nil, err + } + + var res *result + lastErr := tx.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { + res, err = tx.db.simpleQueryData(ctx, cn, model, wb) + return err + }) + + if err := tx.db.afterQuery(ctx, evt, res, err); err != nil { + return nil, err + } + return res, lastErr +} + +// QueryOne is an alias for DB.QueryOne. +func (tx *Tx) QueryOne(model interface{}, query interface{}, params ...interface{}) (Result, error) { + return tx.queryOne(tx.ctx, model, query, params...) +} + +// QueryOneContext acts like QueryOne but additionally receives a context. +func (tx *Tx) QueryOneContext( + c context.Context, + model interface{}, + query interface{}, + params ...interface{}, +) (Result, error) { + return tx.queryOne(c, model, query, params...) +} + +func (tx *Tx) queryOne( + c context.Context, + model interface{}, + query interface{}, + params ...interface{}, +) (Result, error) { + mod, err := orm.NewModel(model) + if err != nil { + return nil, err + } + + res, err := tx.QueryContext(c, mod, query, params...) + if err != nil { + return nil, err + } + + if err := internal.AssertOneRow(res.RowsAffected()); err != nil { + return nil, err + } + return res, nil +} + +// Model is an alias for DB.Model. +func (tx *Tx) Model(model ...interface{}) *Query { + return orm.NewQuery(tx, model...) +} + +// ModelContext acts like Model but additionally receives a context. +func (tx *Tx) ModelContext(c context.Context, model ...interface{}) *Query { + return orm.NewQueryContext(c, tx, model...) +} + +// CopyFrom is an alias for DB.CopyFrom. +func (tx *Tx) CopyFrom(r io.Reader, query interface{}, params ...interface{}) (res Result, err error) { + err = tx.withConn(tx.ctx, func(c context.Context, cn *pool.Conn) error { + res, err = tx.db.copyFrom(c, cn, r, query, params...) + return err + }) + return res, err +} + +// CopyTo is an alias for DB.CopyTo. +func (tx *Tx) CopyTo(w io.Writer, query interface{}, params ...interface{}) (res Result, err error) { + err = tx.withConn(tx.ctx, func(c context.Context, cn *pool.Conn) error { + res, err = tx.db.copyTo(c, cn, w, query, params...) + return err + }) + return res, err +} + +// Formatter is an alias for DB.Formatter. +func (tx *Tx) Formatter() orm.QueryFormatter { + return tx.db.Formatter() +} + +func (tx *Tx) begin(ctx context.Context) error { + var lastErr error + for attempt := 0; attempt <= tx.db.opt.MaxRetries; attempt++ { + if attempt > 0 { + if err := internal.Sleep(ctx, tx.db.retryBackoff(attempt-1)); err != nil { + return err + } + + err := tx.db.pool.(*pool.StickyConnPool).Reset(ctx) + if err != nil { + return err + } + } + + _, lastErr = tx.ExecContext(ctx, "BEGIN") + if !tx.db.shouldRetry(lastErr) { + break + } + } + return lastErr +} + +func (tx *Tx) Commit() error { + return tx.CommitContext(tx.ctx) +} + +// Commit commits the transaction. +func (tx *Tx) CommitContext(ctx context.Context) error { + _, err := tx.ExecContext(internal.UndoContext(ctx), "COMMIT") + tx.close() + return err +} + +func (tx *Tx) Rollback() error { + return tx.RollbackContext(tx.ctx) +} + +// Rollback aborts the transaction. +func (tx *Tx) RollbackContext(ctx context.Context) error { + _, err := tx.ExecContext(internal.UndoContext(ctx), "ROLLBACK") + tx.close() + return err +} + +func (tx *Tx) Close() error { + return tx.CloseContext(tx.ctx) +} + +// Close calls Rollback if the tx has not already been committed or rolled back. +func (tx *Tx) CloseContext(ctx context.Context) error { + if tx.closed() { + return nil + } + return tx.RollbackContext(ctx) +} + +func (tx *Tx) close() { + if !atomic.CompareAndSwapInt32(&tx._closed, 0, 1) { + return + } + + tx.stmtsMu.Lock() + defer tx.stmtsMu.Unlock() + + for _, stmt := range tx.stmts { + _ = stmt.Close() + } + tx.stmts = nil + + _ = tx.db.Close() +} + +func (tx *Tx) closed() bool { + return atomic.LoadInt32(&tx._closed) == 1 +} diff --git a/vendor/github.com/go-pg/pg/v10/types/append.go b/vendor/github.com/go-pg/pg/v10/types/append.go new file mode 100644 index 000000000..342d478b1 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/append.go @@ -0,0 +1,203 @@ +package types + +import ( + "math" + "reflect" + "strconv" + "time" + "unicode/utf8" + + "github.com/tmthrgd/go-hex" +) + +func Append(b []byte, v interface{}, flags int) []byte { + switch v := v.(type) { + case nil: + return AppendNull(b, flags) + case bool: + return appendBool(b, v) + case int32: + return strconv.AppendInt(b, int64(v), 10) + case int64: + return strconv.AppendInt(b, v, 10) + case int: + return strconv.AppendInt(b, int64(v), 10) + case float32: + return appendFloat(b, float64(v), flags, 32) + case float64: + return appendFloat(b, v, flags, 64) + case string: + return AppendString(b, v, flags) + case time.Time: + return AppendTime(b, v, flags) + case []byte: + return AppendBytes(b, v, flags) + case ValueAppender: + return appendAppender(b, v, flags) + default: + return appendValue(b, reflect.ValueOf(v), flags) + } +} + +func AppendError(b []byte, err error) []byte { + b = append(b, "?!("...) + b = append(b, err.Error()...) + b = append(b, ')') + return b +} + +func AppendNull(b []byte, flags int) []byte { + if hasFlag(flags, quoteFlag) { + return append(b, "NULL"...) + } + return nil +} + +func appendBool(dst []byte, v bool) []byte { + if v { + return append(dst, "TRUE"...) + } + return append(dst, "FALSE"...) +} + +func appendFloat(dst []byte, v float64, flags int, bitSize int) []byte { + if hasFlag(flags, arrayFlag) { + return appendFloat2(dst, v, flags) + } + + switch { + case math.IsNaN(v): + if hasFlag(flags, quoteFlag) { + return append(dst, "'NaN'"...) + } + return append(dst, "NaN"...) + case math.IsInf(v, 1): + if hasFlag(flags, quoteFlag) { + return append(dst, "'Infinity'"...) + } + return append(dst, "Infinity"...) + case math.IsInf(v, -1): + if hasFlag(flags, quoteFlag) { + return append(dst, "'-Infinity'"...) + } + return append(dst, "-Infinity"...) + default: + return strconv.AppendFloat(dst, v, 'f', -1, bitSize) + } +} + +func appendFloat2(dst []byte, v float64, _ int) []byte { + switch { + case math.IsNaN(v): + return append(dst, "NaN"...) + case math.IsInf(v, 1): + return append(dst, "Infinity"...) + case math.IsInf(v, -1): + return append(dst, "-Infinity"...) + default: + return strconv.AppendFloat(dst, v, 'f', -1, 64) + } +} + +func AppendString(b []byte, s string, flags int) []byte { + if hasFlag(flags, arrayFlag) { + return appendString2(b, s, flags) + } + + if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + for _, c := range s { + if c == '\000' { + continue + } + + if c == '\'' { + b = append(b, '\'', '\'') + } else { + b = appendRune(b, c) + } + } + b = append(b, '\'') + return b + } + + for _, c := range s { + if c != '\000' { + b = appendRune(b, c) + } + } + return b +} + +func appendString2(b []byte, s string, flags int) []byte { + b = append(b, '"') + for _, c := range s { + if c == '\000' { + continue + } + + switch c { + case '\'': + if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + } + b = append(b, '\'') + case '"': + b = append(b, '\\', '"') + case '\\': + b = append(b, '\\', '\\') + default: + b = appendRune(b, c) + } + } + b = append(b, '"') + return b +} + +func appendRune(b []byte, r rune) []byte { + if r < utf8.RuneSelf { + return append(b, byte(r)) + } + l := len(b) + if cap(b)-l < utf8.UTFMax { + nb := make([]byte, l, 2*l+utf8.UTFMax) + copy(nb, b) + b = nb + } + n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r) + return b[:l+n] +} + +func AppendBytes(b []byte, bytes []byte, flags int) []byte { + if bytes == nil { + return AppendNull(b, flags) + } + + if hasFlag(flags, arrayFlag) { + b = append(b, `"\`...) + } else if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + } + + b = append(b, `\x`...) + + s := len(b) + b = append(b, make([]byte, hex.EncodedLen(len(bytes)))...) + hex.Encode(b[s:], bytes) + + if hasFlag(flags, arrayFlag) { + b = append(b, '"') + } else if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + } + + return b +} + +func appendAppender(b []byte, v ValueAppender, flags int) []byte { + bb, err := v.AppendValue(b, flags) + if err != nil { + return AppendError(b, err) + } + return bb +} diff --git a/vendor/github.com/go-pg/pg/v10/types/append_ident.go b/vendor/github.com/go-pg/pg/v10/types/append_ident.go new file mode 100644 index 000000000..60b9d6784 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/append_ident.go @@ -0,0 +1,46 @@ +package types + +import "github.com/go-pg/pg/v10/internal" + +func AppendIdent(b []byte, field string, flags int) []byte { + return appendIdent(b, internal.StringToBytes(field), flags) +} + +func AppendIdentBytes(b []byte, field []byte, flags int) []byte { + return appendIdent(b, field, flags) +} + +func appendIdent(b, src []byte, flags int) []byte { + var quoted bool +loop: + for _, c := range src { + switch c { + case '*': + if !quoted { + b = append(b, '*') + continue loop + } + case '.': + if quoted && hasFlag(flags, quoteFlag) { + b = append(b, '"') + quoted = false + } + b = append(b, '.') + continue loop + } + + if !quoted && hasFlag(flags, quoteFlag) { + b = append(b, '"') + quoted = true + } + if c == '"' { + b = append(b, '"', '"') + } else { + b = append(b, c) + } + } + if quoted && hasFlag(flags, quoteFlag) { + b = append(b, '"') + } + return b +} diff --git a/vendor/github.com/go-pg/pg/v10/types/append_jsonb.go b/vendor/github.com/go-pg/pg/v10/types/append_jsonb.go new file mode 100644 index 000000000..ffe221825 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/append_jsonb.go @@ -0,0 +1,49 @@ +package types + +import "github.com/go-pg/pg/v10/internal/parser" + +func AppendJSONB(b, jsonb []byte, flags int) []byte { + if hasFlag(flags, arrayFlag) { + b = append(b, '"') + } else if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + } + + p := parser.New(jsonb) + for p.Valid() { + c := p.Read() + switch c { + case '"': + if hasFlag(flags, arrayFlag) { + b = append(b, '\\') + } + b = append(b, '"') + case '\'': + if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + } + b = append(b, '\'') + case '\000': + continue + case '\\': + if p.SkipBytes([]byte("u0000")) { + b = append(b, "\\\\u0000"...) + } else { + b = append(b, '\\') + if p.Valid() { + b = append(b, p.Read()) + } + } + default: + b = append(b, c) + } + } + + if hasFlag(flags, arrayFlag) { + b = append(b, '"') + } else if hasFlag(flags, quoteFlag) { + b = append(b, '\'') + } + + return b +} diff --git a/vendor/github.com/go-pg/pg/v10/types/append_value.go b/vendor/github.com/go-pg/pg/v10/types/append_value.go new file mode 100644 index 000000000..f12fc564f --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/append_value.go @@ -0,0 +1,248 @@ +package types + +import ( + "database/sql/driver" + "fmt" + "net" + "reflect" + "strconv" + "sync" + "time" + + "github.com/vmihailenco/bufpool" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/pgjson" +) + +var ( + driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() + appenderType = reflect.TypeOf((*ValueAppender)(nil)).Elem() +) + +type AppenderFunc func([]byte, reflect.Value, int) []byte + +var appenders []AppenderFunc + +//nolint +func init() { + appenders = []AppenderFunc{ + reflect.Bool: appendBoolValue, + reflect.Int: appendIntValue, + reflect.Int8: appendIntValue, + reflect.Int16: appendIntValue, + reflect.Int32: appendIntValue, + reflect.Int64: appendIntValue, + reflect.Uint: appendUintValue, + reflect.Uint8: appendUintValue, + reflect.Uint16: appendUintValue, + reflect.Uint32: appendUintValue, + reflect.Uint64: appendUintValue, + reflect.Uintptr: nil, + reflect.Float32: appendFloat32Value, + reflect.Float64: appendFloat64Value, + reflect.Complex64: nil, + reflect.Complex128: nil, + reflect.Array: appendJSONValue, + reflect.Chan: nil, + reflect.Func: nil, + reflect.Interface: appendIfaceValue, + reflect.Map: appendJSONValue, + reflect.Ptr: nil, + reflect.Slice: appendJSONValue, + reflect.String: appendStringValue, + reflect.Struct: appendStructValue, + reflect.UnsafePointer: nil, + } +} + +var appendersMap sync.Map + +// RegisterAppender registers an appender func for the value type. +// Expecting to be used only during initialization, it panics +// if there is already a registered appender for the given type. +func RegisterAppender(value interface{}, fn AppenderFunc) { + registerAppender(reflect.TypeOf(value), fn) +} + +func registerAppender(typ reflect.Type, fn AppenderFunc) { + _, loaded := appendersMap.LoadOrStore(typ, fn) + if loaded { + err := fmt.Errorf("pg: appender for the type=%s is already registered", + typ.String()) + panic(err) + } +} + +func Appender(typ reflect.Type) AppenderFunc { + if v, ok := appendersMap.Load(typ); ok { + return v.(AppenderFunc) + } + fn := appender(typ, false) + _, _ = appendersMap.LoadOrStore(typ, fn) + return fn +} + +func appender(typ reflect.Type, pgArray bool) AppenderFunc { + switch typ { + case timeType: + return appendTimeValue + case ipType: + return appendIPValue + case ipNetType: + return appendIPNetValue + case jsonRawMessageType: + return appendJSONRawMessageValue + } + + if typ.Implements(appenderType) { + return appendAppenderValue + } + if typ.Implements(driverValuerType) { + return appendDriverValuerValue + } + + kind := typ.Kind() + switch kind { + case reflect.Ptr: + return ptrAppenderFunc(typ) + case reflect.Slice: + if typ.Elem().Kind() == reflect.Uint8 { + return appendBytesValue + } + if pgArray { + return ArrayAppender(typ) + } + case reflect.Array: + if typ.Elem().Kind() == reflect.Uint8 { + return appendArrayBytesValue + } + } + return appenders[kind] +} + +func ptrAppenderFunc(typ reflect.Type) AppenderFunc { + appender := Appender(typ.Elem()) + return func(b []byte, v reflect.Value, flags int) []byte { + if v.IsNil() { + return AppendNull(b, flags) + } + return appender(b, v.Elem(), flags) + } +} + +func appendValue(b []byte, v reflect.Value, flags int) []byte { + if v.Kind() == reflect.Ptr && v.IsNil() { + return AppendNull(b, flags) + } + appender := Appender(v.Type()) + return appender(b, v, flags) +} + +func appendIfaceValue(b []byte, v reflect.Value, flags int) []byte { + return Append(b, v.Interface(), flags) +} + +func appendBoolValue(b []byte, v reflect.Value, _ int) []byte { + return appendBool(b, v.Bool()) +} + +func appendIntValue(b []byte, v reflect.Value, _ int) []byte { + return strconv.AppendInt(b, v.Int(), 10) +} + +func appendUintValue(b []byte, v reflect.Value, _ int) []byte { + return strconv.AppendUint(b, v.Uint(), 10) +} + +func appendFloat32Value(b []byte, v reflect.Value, flags int) []byte { + return appendFloat(b, v.Float(), flags, 32) +} + +func appendFloat64Value(b []byte, v reflect.Value, flags int) []byte { + return appendFloat(b, v.Float(), flags, 64) +} + +func appendBytesValue(b []byte, v reflect.Value, flags int) []byte { + return AppendBytes(b, v.Bytes(), flags) +} + +func appendArrayBytesValue(b []byte, v reflect.Value, flags int) []byte { + if v.CanAddr() { + return AppendBytes(b, v.Slice(0, v.Len()).Bytes(), flags) + } + + buf := bufpool.Get(v.Len()) + + tmp := buf.Bytes() + reflect.Copy(reflect.ValueOf(tmp), v) + b = AppendBytes(b, tmp, flags) + + bufpool.Put(buf) + + return b +} + +func appendStringValue(b []byte, v reflect.Value, flags int) []byte { + return AppendString(b, v.String(), flags) +} + +func appendStructValue(b []byte, v reflect.Value, flags int) []byte { + if v.Type() == timeType { + return appendTimeValue(b, v, flags) + } + return appendJSONValue(b, v, flags) +} + +var jsonPool bufpool.Pool + +func appendJSONValue(b []byte, v reflect.Value, flags int) []byte { + buf := jsonPool.Get() + defer jsonPool.Put(buf) + + if err := pgjson.NewEncoder(buf).Encode(v.Interface()); err != nil { + return AppendError(b, err) + } + + bb := buf.Bytes() + if len(bb) > 0 && bb[len(bb)-1] == '\n' { + bb = bb[:len(bb)-1] + } + + return AppendJSONB(b, bb, flags) +} + +func appendTimeValue(b []byte, v reflect.Value, flags int) []byte { + tm := v.Interface().(time.Time) + return AppendTime(b, tm, flags) +} + +func appendIPValue(b []byte, v reflect.Value, flags int) []byte { + ip := v.Interface().(net.IP) + return AppendString(b, ip.String(), flags) +} + +func appendIPNetValue(b []byte, v reflect.Value, flags int) []byte { + ipnet := v.Interface().(net.IPNet) + return AppendString(b, ipnet.String(), flags) +} + +func appendJSONRawMessageValue(b []byte, v reflect.Value, flags int) []byte { + return AppendString(b, internal.BytesToString(v.Bytes()), flags) +} + +func appendAppenderValue(b []byte, v reflect.Value, flags int) []byte { + return appendAppender(b, v.Interface().(ValueAppender), flags) +} + +func appendDriverValuerValue(b []byte, v reflect.Value, flags int) []byte { + return appendDriverValuer(b, v.Interface().(driver.Valuer), flags) +} + +func appendDriverValuer(b []byte, v driver.Valuer, flags int) []byte { + value, err := v.Value() + if err != nil { + return AppendError(b, err) + } + return Append(b, value, flags) +} diff --git a/vendor/github.com/go-pg/pg/v10/types/array.go b/vendor/github.com/go-pg/pg/v10/types/array.go new file mode 100644 index 000000000..fb70c1f50 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/array.go @@ -0,0 +1,58 @@ +package types + +import ( + "fmt" + "reflect" +) + +type Array struct { + v reflect.Value + + append AppenderFunc + scan ScannerFunc +} + +var ( + _ ValueAppender = (*Array)(nil) + _ ValueScanner = (*Array)(nil) +) + +func NewArray(vi interface{}) *Array { + v := reflect.ValueOf(vi) + if !v.IsValid() { + panic(fmt.Errorf("pg: Array(nil)")) + } + + return &Array{ + v: v, + + append: ArrayAppender(v.Type()), + scan: ArrayScanner(v.Type()), + } +} + +func (a *Array) AppendValue(b []byte, flags int) ([]byte, error) { + if a.append == nil { + panic(fmt.Errorf("pg: Array(unsupported %s)", a.v.Type())) + } + return a.append(b, a.v, flags), nil +} + +func (a *Array) ScanValue(rd Reader, n int) error { + if a.scan == nil { + return fmt.Errorf("pg: Array(unsupported %s)", a.v.Type()) + } + + if a.v.Kind() != reflect.Ptr { + return fmt.Errorf("pg: Array(non-pointer %s)", a.v.Type()) + } + + return a.scan(a.v.Elem(), rd, n) +} + +func (a *Array) Value() interface{} { + if a.v.IsValid() { + return a.v.Interface() + } + return nil +} diff --git a/vendor/github.com/go-pg/pg/v10/types/array_append.go b/vendor/github.com/go-pg/pg/v10/types/array_append.go new file mode 100644 index 000000000..a4132eb61 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/array_append.go @@ -0,0 +1,236 @@ +package types + +import ( + "reflect" + "strconv" + "sync" +) + +var ( + stringType = reflect.TypeOf((*string)(nil)).Elem() + sliceStringType = reflect.TypeOf([]string(nil)) + + intType = reflect.TypeOf((*int)(nil)).Elem() + sliceIntType = reflect.TypeOf([]int(nil)) + + int64Type = reflect.TypeOf((*int64)(nil)).Elem() + sliceInt64Type = reflect.TypeOf([]int64(nil)) + + float64Type = reflect.TypeOf((*float64)(nil)).Elem() + sliceFloat64Type = reflect.TypeOf([]float64(nil)) +) + +var arrayAppendersMap sync.Map + +func ArrayAppender(typ reflect.Type) AppenderFunc { + if v, ok := arrayAppendersMap.Load(typ); ok { + return v.(AppenderFunc) + } + fn := arrayAppender(typ) + arrayAppendersMap.Store(typ, fn) + return fn +} + +func arrayAppender(typ reflect.Type) AppenderFunc { + kind := typ.Kind() + if kind == reflect.Ptr { + typ = typ.Elem() + kind = typ.Kind() + } + + switch kind { + case reflect.Slice, reflect.Array: + // ok: + default: + return nil + } + + elemType := typ.Elem() + + if kind == reflect.Slice { + switch elemType { + case stringType: + return appendSliceStringValue + case intType: + return appendSliceIntValue + case int64Type: + return appendSliceInt64Value + case float64Type: + return appendSliceFloat64Value + } + } + + appendElem := appender(elemType, true) + return func(b []byte, v reflect.Value, flags int) []byte { + flags |= arrayFlag + + kind := v.Kind() + switch kind { + case reflect.Ptr, reflect.Slice: + if v.IsNil() { + return AppendNull(b, flags) + } + } + + if kind == reflect.Ptr { + v = v.Elem() + } + + quote := shouldQuoteArray(flags) + if quote { + b = append(b, '\'') + } + + flags |= subArrayFlag + + b = append(b, '{') + for i := 0; i < v.Len(); i++ { + elem := v.Index(i) + b = appendElem(b, elem, flags) + b = append(b, ',') + } + if v.Len() > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + if quote { + b = append(b, '\'') + } + + return b + } +} + +func appendSliceStringValue(b []byte, v reflect.Value, flags int) []byte { + ss := v.Convert(sliceStringType).Interface().([]string) + return appendSliceString(b, ss, flags) +} + +func appendSliceString(b []byte, ss []string, flags int) []byte { + if ss == nil { + return AppendNull(b, flags) + } + + quote := shouldQuoteArray(flags) + if quote { + b = append(b, '\'') + } + + b = append(b, '{') + for _, s := range ss { + b = appendString2(b, s, flags) + b = append(b, ',') + } + if len(ss) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + if quote { + b = append(b, '\'') + } + + return b +} + +func appendSliceIntValue(b []byte, v reflect.Value, flags int) []byte { + ints := v.Convert(sliceIntType).Interface().([]int) + return appendSliceInt(b, ints, flags) +} + +func appendSliceInt(b []byte, ints []int, flags int) []byte { + if ints == nil { + return AppendNull(b, flags) + } + + quote := shouldQuoteArray(flags) + if quote { + b = append(b, '\'') + } + + b = append(b, '{') + for _, n := range ints { + b = strconv.AppendInt(b, int64(n), 10) + b = append(b, ',') + } + if len(ints) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + if quote { + b = append(b, '\'') + } + + return b +} + +func appendSliceInt64Value(b []byte, v reflect.Value, flags int) []byte { + ints := v.Convert(sliceInt64Type).Interface().([]int64) + return appendSliceInt64(b, ints, flags) +} + +func appendSliceInt64(b []byte, ints []int64, flags int) []byte { + if ints == nil { + return AppendNull(b, flags) + } + + quote := shouldQuoteArray(flags) + if quote { + b = append(b, '\'') + } + + b = append(b, '{') + for _, n := range ints { + b = strconv.AppendInt(b, n, 10) + b = append(b, ',') + } + if len(ints) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + if quote { + b = append(b, '\'') + } + + return b +} + +func appendSliceFloat64Value(b []byte, v reflect.Value, flags int) []byte { + floats := v.Convert(sliceFloat64Type).Interface().([]float64) + return appendSliceFloat64(b, floats, flags) +} + +func appendSliceFloat64(b []byte, floats []float64, flags int) []byte { + if floats == nil { + return AppendNull(b, flags) + } + + quote := shouldQuoteArray(flags) + if quote { + b = append(b, '\'') + } + + b = append(b, '{') + for _, n := range floats { + b = appendFloat2(b, n, flags) + b = append(b, ',') + } + if len(floats) > 0 { + b[len(b)-1] = '}' // Replace trailing comma. + } else { + b = append(b, '}') + } + + if quote { + b = append(b, '\'') + } + + return b +} diff --git a/vendor/github.com/go-pg/pg/v10/types/array_parser.go b/vendor/github.com/go-pg/pg/v10/types/array_parser.go new file mode 100644 index 000000000..0870a6568 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/array_parser.go @@ -0,0 +1,170 @@ +package types + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + + "github.com/go-pg/pg/v10/internal/parser" +) + +var errEndOfArray = errors.New("pg: end of array") + +type arrayParser struct { + p parser.StreamingParser + + stickyErr error + buf []byte +} + +func newArrayParserErr(err error) *arrayParser { + return &arrayParser{ + stickyErr: err, + buf: make([]byte, 32), + } +} + +func newArrayParser(rd Reader) *arrayParser { + p := parser.NewStreamingParser(rd) + err := p.SkipByte('{') + if err != nil { + return newArrayParserErr(err) + } + return &arrayParser{ + p: p, + } +} + +func (p *arrayParser) NextElem() ([]byte, error) { + if p.stickyErr != nil { + return nil, p.stickyErr + } + + c, err := p.p.ReadByte() + if err != nil { + if err == io.EOF { + return nil, errEndOfArray + } + return nil, err + } + + switch c { + case '"': + b, err := p.p.ReadSubstring(p.buf[:0]) + if err != nil { + return nil, err + } + p.buf = b + + err = p.readCommaBrace() + if err != nil { + return nil, err + } + + return b, nil + case '{': + b, err := p.readSubArray(p.buf[:0]) + if err != nil { + return nil, err + } + p.buf = b + + err = p.readCommaBrace() + if err != nil { + return nil, err + } + + return b, nil + case '}': + return nil, errEndOfArray + default: + err = p.p.UnreadByte() + if err != nil { + return nil, err + } + + b, err := p.readSimple(p.buf[:0]) + if err != nil { + return nil, err + } + p.buf = b + + if bytes.Equal(b, []byte("NULL")) { + return nil, nil + } + return b, nil + } +} + +func (p *arrayParser) readSimple(b []byte) ([]byte, error) { + for { + tmp, err := p.p.ReadSlice(',') + if err == nil { + b = append(b, tmp...) + b = b[:len(b)-1] + break + } + b = append(b, tmp...) + if err == bufio.ErrBufferFull { + continue + } + if err == io.EOF { + if b[len(b)-1] == '}' { + b = b[:len(b)-1] + break + } + } + return nil, err + } + return b, nil +} + +func (p *arrayParser) readSubArray(b []byte) ([]byte, error) { + b = append(b, '{') + for { + c, err := p.p.ReadByte() + if err != nil { + return nil, err + } + + if c == '}' { + b = append(b, '}') + return b, nil + } + + if c == '"' { + b = append(b, '"') + for { + tmp, err := p.p.ReadSlice('"') + b = append(b, tmp...) + if err != nil { + if err == bufio.ErrBufferFull { + continue + } + return nil, err + } + if len(b) > 1 && b[len(b)-2] != '\\' { + break + } + } + continue + } + + b = append(b, c) + } +} + +func (p *arrayParser) readCommaBrace() error { + c, err := p.p.ReadByte() + if err != nil { + return err + } + switch c { + case ',', '}': + return nil + default: + return fmt.Errorf("pg: got %q, wanted ',' or '}'", c) + } +} diff --git a/vendor/github.com/go-pg/pg/v10/types/array_scan.go b/vendor/github.com/go-pg/pg/v10/types/array_scan.go new file mode 100644 index 000000000..dbccafc06 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/array_scan.go @@ -0,0 +1,334 @@ +package types + +import ( + "fmt" + "reflect" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/internal/pool" +) + +var arrayValueScannerType = reflect.TypeOf((*ArrayValueScanner)(nil)).Elem() + +type ArrayValueScanner interface { + BeforeScanArrayValue(rd Reader, n int) error + ScanArrayValue(rd Reader, n int) error + AfterScanArrayValue() error +} + +func ArrayScanner(typ reflect.Type) ScannerFunc { + if typ.Implements(arrayValueScannerType) { + return scanArrayValueScannerValue + } + + kind := typ.Kind() + if kind == reflect.Ptr { + typ = typ.Elem() + kind = typ.Kind() + } + + switch kind { + case reflect.Slice, reflect.Array: + // ok: + default: + return nil + } + + elemType := typ.Elem() + + if kind == reflect.Slice { + switch elemType { + case stringType: + return scanStringArrayValue + case intType: + return scanIntArrayValue + case int64Type: + return scanInt64ArrayValue + case float64Type: + return scanFloat64ArrayValue + } + } + + scanElem := scanner(elemType, true) + return func(v reflect.Value, rd Reader, n int) error { + v = reflect.Indirect(v) + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + + kind := v.Kind() + + if n == -1 { + if kind != reflect.Slice || !v.IsNil() { + v.Set(reflect.Zero(v.Type())) + } + return nil + } + + if kind == reflect.Slice { + if v.IsNil() { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } else if v.Len() > 0 { + v.Set(v.Slice(0, 0)) + } + } + + p := newArrayParser(rd) + nextValue := internal.MakeSliceNextElemFunc(v) + var elemRd *pool.BytesReader + + for { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfArray { + break + } + return err + } + + if elemRd == nil { + elemRd = pool.NewBytesReader(elem) + } else { + elemRd.Reset(elem) + } + + var elemN int + if elem == nil { + elemN = -1 + } else { + elemN = len(elem) + } + + elemValue := nextValue() + err = scanElem(elemValue, elemRd, elemN) + if err != nil { + return err + } + } + + return nil + } +} + +func scanStringArrayValue(v reflect.Value, rd Reader, n int) error { + v = reflect.Indirect(v) + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + + strings, err := scanStringArray(rd, n) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(strings)) + return nil +} + +func scanStringArray(rd Reader, n int) ([]string, error) { + if n == -1 { + return nil, nil + } + + p := newArrayParser(rd) + slice := make([]string, 0) + for { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfArray { + break + } + return nil, err + } + + slice = append(slice, string(elem)) + } + + return slice, nil +} + +func scanIntArrayValue(v reflect.Value, rd Reader, n int) error { + v = reflect.Indirect(v) + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + + slice, err := decodeSliceInt(rd, n) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(slice)) + return nil +} + +func decodeSliceInt(rd Reader, n int) ([]int, error) { + if n == -1 { + return nil, nil + } + + p := newArrayParser(rd) + slice := make([]int, 0) + for { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfArray { + break + } + return nil, err + } + + if elem == nil { + slice = append(slice, 0) + continue + } + + n, err := internal.Atoi(elem) + if err != nil { + return nil, err + } + + slice = append(slice, n) + } + + return slice, nil +} + +func scanInt64ArrayValue(v reflect.Value, rd Reader, n int) error { + v = reflect.Indirect(v) + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + + slice, err := scanInt64Array(rd, n) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(slice)) + return nil +} + +func scanInt64Array(rd Reader, n int) ([]int64, error) { + if n == -1 { + return nil, nil + } + + p := newArrayParser(rd) + slice := make([]int64, 0) + for { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfArray { + break + } + return nil, err + } + + if elem == nil { + slice = append(slice, 0) + continue + } + + n, err := internal.ParseInt(elem, 10, 64) + if err != nil { + return nil, err + } + + slice = append(slice, n) + } + + return slice, nil +} + +func scanFloat64ArrayValue(v reflect.Value, rd Reader, n int) error { + v = reflect.Indirect(v) + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + + slice, err := scanFloat64Array(rd, n) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(slice)) + return nil +} + +func scanFloat64Array(rd Reader, n int) ([]float64, error) { + if n == -1 { + return nil, nil + } + + p := newArrayParser(rd) + slice := make([]float64, 0) + for { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfArray { + break + } + return nil, err + } + + if elem == nil { + slice = append(slice, 0) + continue + } + + n, err := internal.ParseFloat(elem, 64) + if err != nil { + return nil, err + } + + slice = append(slice, n) + } + + return slice, nil +} + +func scanArrayValueScannerValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + return nil + } + + scanner := v.Addr().Interface().(ArrayValueScanner) + + err := scanner.BeforeScanArrayValue(rd, n) + if err != nil { + return err + } + + p := newArrayParser(rd) + var elemRd *pool.BytesReader + for { + elem, err := p.NextElem() + if err != nil { + if err == errEndOfArray { + break + } + return err + } + + if elemRd == nil { + elemRd = pool.NewBytesReader(elem) + } else { + elemRd.Reset(elem) + } + + var elemN int + if elem == nil { + elemN = -1 + } else { + elemN = len(elem) + } + + err = scanner.ScanArrayValue(elemRd, elemN) + if err != nil { + return err + } + } + + return scanner.AfterScanArrayValue() +} diff --git a/vendor/github.com/go-pg/pg/v10/types/column.go b/vendor/github.com/go-pg/pg/v10/types/column.go new file mode 100644 index 000000000..e3470f3eb --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/column.go @@ -0,0 +1,113 @@ +package types + +import ( + "encoding/json" + + "github.com/go-pg/pg/v10/internal/pool" + "github.com/go-pg/pg/v10/pgjson" +) + +const ( + pgBool = 16 + + pgInt2 = 21 + pgInt4 = 23 + pgInt8 = 20 + + pgFloat4 = 700 + pgFloat8 = 701 + + pgText = 25 + pgVarchar = 1043 + pgBytea = 17 + pgJSON = 114 + pgJSONB = 3802 + + pgTimestamp = 1114 + pgTimestamptz = 1184 + + // pgInt2Array = 1005 + pgInt32Array = 1007 + pgInt8Array = 1016 + pgFloat8Array = 1022 + pgStringArray = 1009 + + pgUUID = 2950 +) + +type ColumnInfo = pool.ColumnInfo + +type RawValue struct { + Type int32 + Value string +} + +func (v RawValue) AppendValue(b []byte, flags int) ([]byte, error) { + return AppendString(b, v.Value, flags), nil +} + +func (v RawValue) MarshalJSON() ([]byte, error) { + return pgjson.Marshal(v.Value) +} + +func ReadColumnValue(col ColumnInfo, rd Reader, n int) (interface{}, error) { + switch col.DataType { + case pgBool: + return ScanBool(rd, n) + + case pgInt2: + n, err := scanInt64(rd, n, 16) + if err != nil { + return nil, err + } + return int16(n), nil + case pgInt4: + n, err := scanInt64(rd, n, 32) + if err != nil { + return nil, err + } + return int32(n), nil + case pgInt8: + return ScanInt64(rd, n) + + case pgFloat4: + return ScanFloat32(rd, n) + case pgFloat8: + return ScanFloat64(rd, n) + + case pgBytea: + return ScanBytes(rd, n) + case pgText, pgVarchar, pgUUID: + return ScanString(rd, n) + case pgJSON, pgJSONB: + s, err := ScanString(rd, n) + if err != nil { + return nil, err + } + return json.RawMessage(s), nil + + case pgTimestamp: + return ScanTime(rd, n) + case pgTimestamptz: + return ScanTime(rd, n) + + case pgInt32Array: + return scanInt64Array(rd, n) + case pgInt8Array: + return scanInt64Array(rd, n) + case pgFloat8Array: + return scanFloat64Array(rd, n) + case pgStringArray: + return scanStringArray(rd, n) + + default: + s, err := ScanString(rd, n) + if err != nil { + return nil, err + } + return RawValue{ + Type: col.DataType, + Value: s, + }, nil + } +} diff --git a/vendor/github.com/go-pg/pg/v10/types/doc.go b/vendor/github.com/go-pg/pg/v10/types/doc.go new file mode 100644 index 000000000..890ef3c08 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/doc.go @@ -0,0 +1,4 @@ +/* +The API in this package is not stable and may change without any notice. +*/ +package types diff --git a/vendor/github.com/go-pg/pg/v10/types/flags.go b/vendor/github.com/go-pg/pg/v10/types/flags.go new file mode 100644 index 000000000..10e415f14 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/flags.go @@ -0,0 +1,25 @@ +package types + +import "reflect" + +const ( + quoteFlag = 1 << iota + arrayFlag + subArrayFlag +) + +func hasFlag(flags, flag int) bool { + return flags&flag == flag +} + +func shouldQuoteArray(flags int) bool { + return hasFlag(flags, quoteFlag) && !hasFlag(flags, subArrayFlag) +} + +func nilable(v reflect.Value) bool { + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return true + } + return false +} diff --git a/vendor/github.com/go-pg/pg/v10/types/hex.go b/vendor/github.com/go-pg/pg/v10/types/hex.go new file mode 100644 index 000000000..8ae6469b9 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/hex.go @@ -0,0 +1,81 @@ +package types + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + + fasthex "github.com/tmthrgd/go-hex" +) + +type HexEncoder struct { + b []byte + flags int + written bool +} + +func NewHexEncoder(b []byte, flags int) *HexEncoder { + return &HexEncoder{ + b: b, + flags: flags, + } +} + +func (enc *HexEncoder) Bytes() []byte { + return enc.b +} + +func (enc *HexEncoder) Write(b []byte) (int, error) { + if !enc.written { + if hasFlag(enc.flags, arrayFlag) { + enc.b = append(enc.b, `"\`...) + } else if hasFlag(enc.flags, quoteFlag) { + enc.b = append(enc.b, '\'') + } + enc.b = append(enc.b, `\x`...) + enc.written = true + } + + i := len(enc.b) + enc.b = append(enc.b, make([]byte, fasthex.EncodedLen(len(b)))...) + fasthex.Encode(enc.b[i:], b) + + return len(b), nil +} + +func (enc *HexEncoder) Close() error { + if enc.written { + if hasFlag(enc.flags, arrayFlag) { + enc.b = append(enc.b, '"') + } else if hasFlag(enc.flags, quoteFlag) { + enc.b = append(enc.b, '\'') + } + } else { + enc.b = AppendNull(enc.b, enc.flags) + } + return nil +} + +//------------------------------------------------------------------------------ + +func NewHexDecoder(rd Reader, n int) (io.Reader, error) { + if n <= 0 { + var rd bytes.Reader + return &rd, nil + } + + if c, err := rd.ReadByte(); err != nil { + return nil, err + } else if c != '\\' { + return nil, fmt.Errorf("got %q, wanted %q", c, '\\') + } + + if c, err := rd.ReadByte(); err != nil { + return nil, err + } else if c != 'x' { + return nil, fmt.Errorf("got %q, wanted %q", c, 'x') + } + + return hex.NewDecoder(rd), nil +} diff --git a/vendor/github.com/go-pg/pg/v10/types/hstore.go b/vendor/github.com/go-pg/pg/v10/types/hstore.go new file mode 100644 index 000000000..58c214ac6 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/hstore.go @@ -0,0 +1,59 @@ +package types + +import ( + "fmt" + "reflect" +) + +type Hstore struct { + v reflect.Value + + append AppenderFunc + scan ScannerFunc +} + +var ( + _ ValueAppender = (*Hstore)(nil) + _ ValueScanner = (*Hstore)(nil) +) + +func NewHstore(vi interface{}) *Hstore { + v := reflect.ValueOf(vi) + if !v.IsValid() { + panic(fmt.Errorf("pg.Hstore(nil)")) + } + + typ := v.Type() + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + if typ.Kind() != reflect.Map { + panic(fmt.Errorf("pg.Hstore(unsupported %s)", typ)) + } + + return &Hstore{ + v: v, + + append: HstoreAppender(typ), + scan: HstoreScanner(typ), + } +} + +func (h *Hstore) Value() interface{} { + if h.v.IsValid() { + return h.v.Interface() + } + return nil +} + +func (h *Hstore) AppendValue(b []byte, flags int) ([]byte, error) { + return h.append(b, h.v, flags), nil +} + +func (h *Hstore) ScanValue(rd Reader, n int) error { + if h.v.Kind() != reflect.Ptr { + return fmt.Errorf("pg: Hstore(non-pointer %s)", h.v.Type()) + } + + return h.scan(h.v.Elem(), rd, n) +} diff --git a/vendor/github.com/go-pg/pg/types/append_hstore.go b/vendor/github.com/go-pg/pg/v10/types/hstore_append.go similarity index 63% rename from vendor/github.com/go-pg/pg/types/append_hstore.go rename to vendor/github.com/go-pg/pg/v10/types/hstore_append.go index 954907433..e27292afa 100644 --- a/vendor/github.com/go-pg/pg/types/append_hstore.go +++ b/vendor/github.com/go-pg/pg/v10/types/hstore_append.go @@ -11,39 +11,40 @@ func HstoreAppender(typ reflect.Type) AppenderFunc { if typ.Key() == stringType && typ.Elem() == stringType { return appendMapStringStringValue } - return func(b []byte, v reflect.Value, quote int) []byte { + + return func(b []byte, v reflect.Value, flags int) []byte { err := fmt.Errorf("pg.Hstore(unsupported %s)", v.Type()) return AppendError(b, err) } } -func appendMapStringString(b []byte, m map[string]string, quote int) []byte { +func appendMapStringString(b []byte, m map[string]string, flags int) []byte { if m == nil { - return AppendNull(b, quote) + return AppendNull(b, flags) } - if quote == 1 { + if hasFlag(flags, quoteFlag) { b = append(b, '\'') } for key, value := range m { - b = AppendString(b, key, 2) + b = appendString2(b, key, flags) b = append(b, '=', '>') - b = AppendString(b, value, 2) + b = appendString2(b, value, flags) b = append(b, ',') } if len(m) > 0 { b = b[:len(b)-1] // Strip trailing comma. } - if quote == 1 { + if hasFlag(flags, quoteFlag) { b = append(b, '\'') } return b } -func appendMapStringStringValue(b []byte, v reflect.Value, quote int) []byte { +func appendMapStringStringValue(b []byte, v reflect.Value, flags int) []byte { m := v.Convert(mapStringStringType).Interface().(map[string]string) - return appendMapStringString(b, m, quote) + return appendMapStringString(b, m, flags) } diff --git a/vendor/github.com/go-pg/pg/v10/types/hstore_parser.go b/vendor/github.com/go-pg/pg/v10/types/hstore_parser.go new file mode 100644 index 000000000..79cd41eda --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/hstore_parser.go @@ -0,0 +1,65 @@ +package types + +import ( + "errors" + "io" + + "github.com/go-pg/pg/v10/internal/parser" +) + +var errEndOfHstore = errors.New("pg: end of hstore") + +type hstoreParser struct { + p parser.StreamingParser +} + +func newHstoreParser(rd Reader) *hstoreParser { + return &hstoreParser{ + p: parser.NewStreamingParser(rd), + } +} + +func (p *hstoreParser) NextKey() ([]byte, error) { + err := p.p.SkipByte('"') + if err != nil { + if err == io.EOF { + return nil, errEndOfHstore + } + return nil, err + } + + key, err := p.p.ReadSubstring(nil) + if err != nil { + return nil, err + } + + err = p.p.SkipByte('=') + if err != nil { + return nil, err + } + err = p.p.SkipByte('>') + if err != nil { + return nil, err + } + + return key, nil +} + +func (p *hstoreParser) NextValue() ([]byte, error) { + err := p.p.SkipByte('"') + if err != nil { + return nil, err + } + + value, err := p.p.ReadSubstring(nil) + if err != nil { + return nil, err + } + + err = p.p.SkipByte(',') + if err == nil { + _ = p.p.SkipByte(' ') + } + + return value, nil +} diff --git a/vendor/github.com/go-pg/pg/types/scan_hstore.go b/vendor/github.com/go-pg/pg/v10/types/hstore_scan.go similarity index 51% rename from vendor/github.com/go-pg/pg/types/scan_hstore.go rename to vendor/github.com/go-pg/pg/v10/types/hstore_scan.go index ee5b62833..2061c6163 100644 --- a/vendor/github.com/go-pg/pg/types/scan_hstore.go +++ b/vendor/github.com/go-pg/pg/v10/types/hstore_scan.go @@ -3,56 +3,49 @@ package types import ( "fmt" "reflect" - - "github.com/go-pg/pg/internal/parser" ) func HstoreScanner(typ reflect.Type) ScannerFunc { if typ.Key() == stringType && typ.Elem() == stringType { return scanMapStringStringValue } - return func(v reflect.Value, b []byte) error { + return func(v reflect.Value, rd Reader, n int) error { return fmt.Errorf("pg.Hstore(unsupported %s)", v.Type()) } } -func scanMapStringString(b []byte) (map[string]string, error) { - if b == nil { +func scanMapStringStringValue(v reflect.Value, rd Reader, n int) error { + m, err := scanMapStringString(rd, n) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(m)) + return nil +} + +func scanMapStringString(rd Reader, n int) (map[string]string, error) { + if n == -1 { return nil, nil } - p := parser.NewHstoreParser(b) + p := newHstoreParser(rd) m := make(map[string]string) - for p.Valid() { + for { key, err := p.NextKey() if err != nil { + if err == errEndOfHstore { + break + } return nil, err } - if key == nil { - return nil, fmt.Errorf("pg: unexpected NULL: %q", b) - } value, err := p.NextValue() if err != nil { return nil, err } - if value == nil { - return nil, fmt.Errorf("pg: unexpected NULL: %q", b) - } m[string(key)] = string(value) } return m, nil } - -func scanMapStringStringValue(v reflect.Value, b []byte) error { - if !v.CanSet() { - return fmt.Errorf("pg: Scan(nonsettable %s)", v.Type()) - } - m, err := scanMapStringString(b) - if err != nil { - return err - } - v.Set(reflect.ValueOf(m)) - return nil -} diff --git a/vendor/github.com/go-pg/pg/v10/types/in_op.go b/vendor/github.com/go-pg/pg/v10/types/in_op.go new file mode 100644 index 000000000..472b986d8 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/in_op.go @@ -0,0 +1,62 @@ +package types + +import ( + "fmt" + "reflect" +) + +type inOp struct { + slice reflect.Value + stickyErr error +} + +var _ ValueAppender = (*inOp)(nil) + +func InMulti(values ...interface{}) ValueAppender { + return &inOp{ + slice: reflect.ValueOf(values), + } +} + +func In(slice interface{}) ValueAppender { + v := reflect.ValueOf(slice) + if v.Kind() != reflect.Slice { + return &inOp{ + stickyErr: fmt.Errorf("pg: In(non-slice %T)", slice), + } + } + + return &inOp{ + slice: v, + } +} + +func (in *inOp) AppendValue(b []byte, flags int) ([]byte, error) { + if in.stickyErr != nil { + return nil, in.stickyErr + } + return appendIn(b, in.slice, flags), nil +} + +func appendIn(b []byte, slice reflect.Value, flags int) []byte { + sliceLen := slice.Len() + for i := 0; i < sliceLen; i++ { + if i > 0 { + b = append(b, ',') + } + + elem := slice.Index(i) + if elem.Kind() == reflect.Interface { + elem = elem.Elem() + } + + if elem.Kind() == reflect.Slice { + b = append(b, '(') + b = appendIn(b, elem, flags) + b = append(b, ')') + } else { + b = appendValue(b, elem, flags) + } + } + return b +} diff --git a/vendor/github.com/go-pg/pg/time.go b/vendor/github.com/go-pg/pg/v10/types/null_time.go similarity index 64% rename from vendor/github.com/go-pg/pg/time.go rename to vendor/github.com/go-pg/pg/v10/types/null_time.go index 66964fad6..3c3f1f79a 100644 --- a/vendor/github.com/go-pg/pg/time.go +++ b/vendor/github.com/go-pg/pg/v10/types/null_time.go @@ -1,12 +1,10 @@ -package pg +package types import ( "bytes" "database/sql" "encoding/json" "time" - - "github.com/go-pg/pg/types" ) var jsonNull = []byte("null") @@ -17,10 +15,12 @@ type NullTime struct { time.Time } -var _ json.Marshaler = (*NullTime)(nil) -var _ json.Unmarshaler = (*NullTime)(nil) -var _ sql.Scanner = (*NullTime)(nil) -var _ types.ValueAppender = (*NullTime)(nil) +var ( + _ json.Marshaler = (*NullTime)(nil) + _ json.Unmarshaler = (*NullTime)(nil) + _ sql.Scanner = (*NullTime)(nil) + _ ValueAppender = (*NullTime)(nil) +) func (tm NullTime) MarshalJSON() ([]byte, error) { if tm.IsZero() { @@ -37,11 +37,11 @@ func (tm *NullTime) UnmarshalJSON(b []byte) error { return tm.Time.UnmarshalJSON(b) } -func (tm NullTime) AppendValue(b []byte, quote int) []byte { +func (tm NullTime) AppendValue(b []byte, flags int) ([]byte, error) { if tm.IsZero() { - return types.AppendNull(b, quote) + return AppendNull(b, flags), nil } - return types.AppendTime(b, tm.Time, quote) + return AppendTime(b, tm.Time, flags), nil } func (tm *NullTime) Scan(b interface{}) error { @@ -49,7 +49,7 @@ func (tm *NullTime) Scan(b interface{}) error { tm.Time = time.Time{} return nil } - newtm, err := types.ParseTime(b.([]byte)) + newtm, err := ParseTime(b.([]byte)) if err != nil { return err } diff --git a/vendor/github.com/go-pg/pg/v10/types/scan.go b/vendor/github.com/go-pg/pg/v10/types/scan.go new file mode 100644 index 000000000..2e9c0cc85 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/scan.go @@ -0,0 +1,244 @@ +package types + +import ( + "errors" + "fmt" + "reflect" + "time" + + "github.com/tmthrgd/go-hex" + + "github.com/go-pg/pg/v10/internal" +) + +func Scan(v interface{}, rd Reader, n int) error { + var err error + switch v := v.(type) { + case *string: + *v, err = ScanString(rd, n) + return err + case *[]byte: + *v, err = ScanBytes(rd, n) + return err + case *int: + *v, err = ScanInt(rd, n) + return err + case *int64: + *v, err = ScanInt64(rd, n) + return err + case *float32: + *v, err = ScanFloat32(rd, n) + return err + case *float64: + *v, err = ScanFloat64(rd, n) + return err + case *time.Time: + *v, err = ScanTime(rd, n) + return err + } + + vv := reflect.ValueOf(v) + if !vv.IsValid() { + return errors.New("pg: Scan(nil)") + } + + if vv.Kind() != reflect.Ptr { + return fmt.Errorf("pg: Scan(non-pointer %T)", v) + } + if vv.IsNil() { + return fmt.Errorf("pg: Scan(non-settable %T)", v) + } + + vv = vv.Elem() + if vv.Kind() == reflect.Interface { + if vv.IsNil() { + return errors.New("pg: Scan(nil)") + } + + vv = vv.Elem() + if vv.Kind() != reflect.Ptr { + return fmt.Errorf("pg: Decode(non-pointer %s)", vv.Type().String()) + } + } + + return ScanValue(vv, rd, n) +} + +func ScanString(rd Reader, n int) (string, error) { + if n <= 0 { + return "", nil + } + + b, err := rd.ReadFull() + if err != nil { + return "", err + } + + return internal.BytesToString(b), nil +} + +func ScanBytes(rd Reader, n int) ([]byte, error) { + if n == -1 { + return nil, nil + } + if n == 0 { + return []byte{}, nil + } + + b := make([]byte, hex.DecodedLen(n-2)) + if err := ReadBytes(rd, b); err != nil { + return nil, err + } + return b, nil +} + +func ReadBytes(rd Reader, b []byte) error { + tmp, err := rd.ReadFullTemp() + if err != nil { + return err + } + + if len(tmp) < 2 { + return fmt.Errorf("pg: can't parse bytea: %q", tmp) + } + + if tmp[0] != '\\' || tmp[1] != 'x' { + return fmt.Errorf("pg: can't parse bytea: %q", tmp) + } + tmp = tmp[2:] // Trim off "\\x". + + if len(b) != hex.DecodedLen(len(tmp)) { + return fmt.Errorf("pg: too small buf to decode hex") + } + + if _, err := hex.Decode(b, tmp); err != nil { + return err + } + + return nil +} + +func ScanInt(rd Reader, n int) (int, error) { + if n <= 0 { + return 0, nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return 0, err + } + + num, err := internal.Atoi(tmp) + if err != nil { + return 0, err + } + + return num, nil +} + +func ScanInt64(rd Reader, n int) (int64, error) { + return scanInt64(rd, n, 64) +} + +func scanInt64(rd Reader, n int, bitSize int) (int64, error) { + if n <= 0 { + return 0, nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return 0, err + } + + num, err := internal.ParseInt(tmp, 10, bitSize) + if err != nil { + return 0, err + } + + return num, nil +} + +func ScanUint64(rd Reader, n int) (uint64, error) { + if n <= 0 { + return 0, nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return 0, err + } + + // PostgreSQL does not natively support uint64 - only int64. + // Be nice and accept negative int64. + if len(tmp) > 0 && tmp[0] == '-' { + num, err := internal.ParseInt(tmp, 10, 64) + if err != nil { + return 0, err + } + return uint64(num), nil + } + + num, err := internal.ParseUint(tmp, 10, 64) + if err != nil { + return 0, err + } + + return num, nil +} + +func ScanFloat32(rd Reader, n int) (float32, error) { + if n <= 0 { + return 0, nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return 0, err + } + + num, err := internal.ParseFloat(tmp, 32) + if err != nil { + return 0, err + } + + return float32(num), nil +} + +func ScanFloat64(rd Reader, n int) (float64, error) { + if n <= 0 { + return 0, nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return 0, err + } + + num, err := internal.ParseFloat(tmp, 64) + if err != nil { + return 0, err + } + + return num, nil +} + +func ScanTime(rd Reader, n int) (time.Time, error) { + if n <= 0 { + return time.Time{}, nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return time.Time{}, err + } + + return ParseTime(tmp) +} + +func ScanBool(rd Reader, n int) (bool, error) { + tmp, err := rd.ReadFullTemp() + if err != nil { + return false, err + } + return len(tmp) == 1 && (tmp[0] == 't' || tmp[0] == '1'), nil +} diff --git a/vendor/github.com/go-pg/pg/v10/types/scan_value.go b/vendor/github.com/go-pg/pg/v10/types/scan_value.go new file mode 100644 index 000000000..9f5a7bb6e --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/scan_value.go @@ -0,0 +1,418 @@ +package types + +import ( + "database/sql" + "encoding/json" + "errors" + "fmt" + "net" + "reflect" + "sync" + "time" + + "github.com/go-pg/pg/v10/internal" + "github.com/go-pg/pg/v10/pgjson" +) + +var ( + valueScannerType = reflect.TypeOf((*ValueScanner)(nil)).Elem() + sqlScannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem() + timeType = reflect.TypeOf((*time.Time)(nil)).Elem() + ipType = reflect.TypeOf((*net.IP)(nil)).Elem() + ipNetType = reflect.TypeOf((*net.IPNet)(nil)).Elem() + jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem() +) + +type ScannerFunc func(reflect.Value, Reader, int) error + +var valueScanners []ScannerFunc + +//nolint +func init() { + valueScanners = []ScannerFunc{ + reflect.Bool: scanBoolValue, + reflect.Int: scanInt64Value, + reflect.Int8: scanInt64Value, + reflect.Int16: scanInt64Value, + reflect.Int32: scanInt64Value, + reflect.Int64: scanInt64Value, + reflect.Uint: scanUint64Value, + reflect.Uint8: scanUint64Value, + reflect.Uint16: scanUint64Value, + reflect.Uint32: scanUint64Value, + reflect.Uint64: scanUint64Value, + reflect.Uintptr: nil, + reflect.Float32: scanFloat32Value, + reflect.Float64: scanFloat64Value, + reflect.Complex64: nil, + reflect.Complex128: nil, + reflect.Array: scanJSONValue, + reflect.Chan: nil, + reflect.Func: nil, + reflect.Interface: scanIfaceValue, + reflect.Map: scanJSONValue, + reflect.Ptr: nil, + reflect.Slice: scanJSONValue, + reflect.String: scanStringValue, + reflect.Struct: scanJSONValue, + reflect.UnsafePointer: nil, + } +} + +var scannersMap sync.Map + +// RegisterScanner registers an scanner func for the type. +// Expecting to be used only during initialization, it panics +// if there is already a registered scanner for the given type. +func RegisterScanner(value interface{}, fn ScannerFunc) { + registerScanner(reflect.TypeOf(value), fn) +} + +func registerScanner(typ reflect.Type, fn ScannerFunc) { + _, loaded := scannersMap.LoadOrStore(typ, fn) + if loaded { + err := fmt.Errorf("pg: scanner for the type=%s is already registered", + typ.String()) + panic(err) + } +} + +func Scanner(typ reflect.Type) ScannerFunc { + if v, ok := scannersMap.Load(typ); ok { + return v.(ScannerFunc) + } + fn := scanner(typ, false) + _, _ = scannersMap.LoadOrStore(typ, fn) + return fn +} + +func scanner(typ reflect.Type, pgArray bool) ScannerFunc { + switch typ { + case timeType: + return scanTimeValue + case ipType: + return scanIPValue + case ipNetType: + return scanIPNetValue + case jsonRawMessageType: + return scanJSONRawMessageValue + } + + if typ.Implements(valueScannerType) { + return scanValueScannerValue + } + if reflect.PtrTo(typ).Implements(valueScannerType) { + return scanValueScannerAddrValue + } + + if typ.Implements(sqlScannerType) { + return scanSQLScannerValue + } + if reflect.PtrTo(typ).Implements(sqlScannerType) { + return scanSQLScannerAddrValue + } + + kind := typ.Kind() + switch kind { + case reflect.Ptr: + return ptrScannerFunc(typ) + case reflect.Slice: + if typ.Elem().Kind() == reflect.Uint8 { + return scanBytesValue + } + if pgArray { + return ArrayScanner(typ) + } + case reflect.Array: + if typ.Elem().Kind() == reflect.Uint8 { + return scanArrayBytesValue + } + } + return valueScanners[kind] +} + +func ptrScannerFunc(typ reflect.Type) ScannerFunc { + scanner := Scanner(typ.Elem()) + return func(v reflect.Value, rd Reader, n int) error { + if scanner == nil { + return fmt.Errorf("pg: Scan(unsupported %s)", v.Type()) + } + + if n == -1 { + if v.IsNil() { + return nil + } + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + v.Set(reflect.Zero(v.Type())) + return nil + } + + if v.IsNil() { + if !v.CanSet() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + v.Set(reflect.New(v.Type().Elem())) + } + + return scanner(v.Elem(), rd, n) + } +} + +func scanIfaceValue(v reflect.Value, rd Reader, n int) error { + if v.IsNil() { + return scanJSONValue(v, rd, n) + } + return ScanValue(v.Elem(), rd, n) +} + +func ScanValue(v reflect.Value, rd Reader, n int) error { + if !v.IsValid() { + return errors.New("pg: Scan(nil)") + } + + scanner := Scanner(v.Type()) + if scanner != nil { + return scanner(v, rd, n) + } + + if v.Kind() == reflect.Interface { + return errors.New("pg: Scan(nil)") + } + return fmt.Errorf("pg: Scan(unsupported %s)", v.Type()) +} + +func scanBoolValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + v.SetBool(false) + return nil + } + + flag, err := ScanBool(rd, n) + if err != nil { + return err + } + + v.SetBool(flag) + return nil +} + +func scanInt64Value(v reflect.Value, rd Reader, n int) error { + num, err := ScanInt64(rd, n) + if err != nil { + return err + } + + v.SetInt(num) + return nil +} + +func scanUint64Value(v reflect.Value, rd Reader, n int) error { + num, err := ScanUint64(rd, n) + if err != nil { + return err + } + + v.SetUint(num) + return nil +} + +func scanFloat32Value(v reflect.Value, rd Reader, n int) error { + num, err := ScanFloat32(rd, n) + if err != nil { + return err + } + + v.SetFloat(float64(num)) + return nil +} + +func scanFloat64Value(v reflect.Value, rd Reader, n int) error { + num, err := ScanFloat64(rd, n) + if err != nil { + return err + } + + v.SetFloat(num) + return nil +} + +func scanStringValue(v reflect.Value, rd Reader, n int) error { + s, err := ScanString(rd, n) + if err != nil { + return err + } + + v.SetString(s) + return nil +} + +func scanJSONValue(v reflect.Value, rd Reader, n int) error { + // Zero value so it works with SelectOrInsert. + // TODO: better handle slices + v.Set(reflect.New(v.Type()).Elem()) + + if n == -1 { + return nil + } + + dec := pgjson.NewDecoder(rd) + return dec.Decode(v.Addr().Interface()) +} + +func scanTimeValue(v reflect.Value, rd Reader, n int) error { + tm, err := ScanTime(rd, n) + if err != nil { + return err + } + + ptr := v.Addr().Interface().(*time.Time) + *ptr = tm + + return nil +} + +func scanIPValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + return nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return err + } + + ip := net.ParseIP(internal.BytesToString(tmp)) + if ip == nil { + return fmt.Errorf("pg: invalid ip=%q", tmp) + } + + ptr := v.Addr().Interface().(*net.IP) + *ptr = ip + + return nil +} + +var zeroIPNetValue = reflect.ValueOf(net.IPNet{}) + +func scanIPNetValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + v.Set(zeroIPNetValue) + return nil + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return err + } + + _, ipnet, err := net.ParseCIDR(internal.BytesToString(tmp)) + if err != nil { + return err + } + + ptr := v.Addr().Interface().(*net.IPNet) + *ptr = *ipnet + + return nil +} + +func scanJSONRawMessageValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + v.SetBytes(nil) + return nil + } + + b, err := rd.ReadFull() + if err != nil { + return err + } + + v.SetBytes(b) + return nil +} + +func scanBytesValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + v.SetBytes(nil) + return nil + } + + b, err := ScanBytes(rd, n) + if err != nil { + return err + } + + v.SetBytes(b) + return nil +} + +func scanArrayBytesValue(v reflect.Value, rd Reader, n int) error { + b := v.Slice(0, v.Len()).Bytes() + + if n == -1 { + for i := range b { + b[i] = 0 + } + return nil + } + + return ReadBytes(rd, b) +} + +func scanValueScannerValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + if v.IsNil() { + return nil + } + return v.Interface().(ValueScanner).ScanValue(rd, n) + } + + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + + return v.Interface().(ValueScanner).ScanValue(rd, n) +} + +func scanValueScannerAddrValue(v reflect.Value, rd Reader, n int) error { + if !v.CanAddr() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + return v.Addr().Interface().(ValueScanner).ScanValue(rd, n) +} + +func scanSQLScannerValue(v reflect.Value, rd Reader, n int) error { + if n == -1 { + if nilable(v) && v.IsNil() { + return nil + } + return scanSQLScanner(v.Interface().(sql.Scanner), rd, n) + } + + if nilable(v) && v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + + return scanSQLScanner(v.Interface().(sql.Scanner), rd, n) +} + +func scanSQLScannerAddrValue(v reflect.Value, rd Reader, n int) error { + if !v.CanAddr() { + return fmt.Errorf("pg: Scan(non-settable %s)", v.Type()) + } + return scanSQLScanner(v.Addr().Interface().(sql.Scanner), rd, n) +} + +func scanSQLScanner(scanner sql.Scanner, rd Reader, n int) error { + if n == -1 { + return scanner.Scan(nil) + } + + tmp, err := rd.ReadFullTemp() + if err != nil { + return err + } + return scanner.Scan(tmp) +} diff --git a/vendor/github.com/go-pg/pg/types/time.go b/vendor/github.com/go-pg/pg/v10/types/time.go similarity index 90% rename from vendor/github.com/go-pg/pg/types/time.go rename to vendor/github.com/go-pg/pg/v10/types/time.go index 30c3ed260..e68a7a19a 100644 --- a/vendor/github.com/go-pg/pg/types/time.go +++ b/vendor/github.com/go-pg/pg/v10/types/time.go @@ -3,7 +3,7 @@ package types import ( "time" - "github.com/go-pg/pg/internal" + "github.com/go-pg/pg/v10/internal" ) const ( @@ -44,12 +44,12 @@ func ParseTimeString(s string) (time.Time, error) { } } -func AppendTime(b []byte, tm time.Time, quote int) []byte { - if quote == 1 { +func AppendTime(b []byte, tm time.Time, flags int) []byte { + if flags == 1 { b = append(b, '\'') } b = tm.UTC().AppendFormat(b, timestamptzFormat) - if quote == 1 { + if flags == 1 { b = append(b, '\'') } return b diff --git a/vendor/github.com/go-pg/pg/v10/types/types.go b/vendor/github.com/go-pg/pg/v10/types/types.go new file mode 100644 index 000000000..718ac2933 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/types/types.go @@ -0,0 +1,37 @@ +package types + +import ( + "github.com/go-pg/pg/v10/internal/pool" +) + +type Reader = pool.Reader + +type ValueScanner interface { + ScanValue(rd Reader, n int) error +} + +type ValueAppender interface { + AppendValue(b []byte, flags int) ([]byte, error) +} + +//------------------------------------------------------------------------------ + +// Safe represents a safe SQL query. +type Safe string + +var _ ValueAppender = (*Safe)(nil) + +func (q Safe) AppendValue(b []byte, flags int) ([]byte, error) { + return append(b, q...), nil +} + +//------------------------------------------------------------------------------ + +// Ident represents a SQL identifier, e.g. table or column name. +type Ident string + +var _ ValueAppender = (*Ident)(nil) + +func (f Ident) AppendValue(b []byte, flags int) ([]byte, error) { + return AppendIdent(b, string(f), flags), nil +} diff --git a/vendor/github.com/go-pg/pg/v10/version.go b/vendor/github.com/go-pg/pg/v10/version.go new file mode 100644 index 000000000..8671ea8c0 --- /dev/null +++ b/vendor/github.com/go-pg/pg/v10/version.go @@ -0,0 +1,6 @@ +package pg + +// Version is the current release version. +func Version() string { + return "10.12.0" +} diff --git a/vendor/github.com/go-pg/zerochecker/LICENSE b/vendor/github.com/go-pg/zerochecker/LICENSE new file mode 100644 index 000000000..7751509b8 --- /dev/null +++ b/vendor/github.com/go-pg/zerochecker/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2013 github.com/go-pg/pg 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. + +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. diff --git a/vendor/github.com/go-pg/pg/orm/zero.go b/vendor/github.com/go-pg/zerochecker/zerochecker.go similarity index 74% rename from vendor/github.com/go-pg/pg/orm/zero.go rename to vendor/github.com/go-pg/zerochecker/zerochecker.go index 659293f01..61bd207c9 100644 --- a/vendor/github.com/go-pg/pg/orm/zero.go +++ b/vendor/github.com/go-pg/zerochecker/zerochecker.go @@ -1,23 +1,27 @@ -package orm +package zerochecker import ( "database/sql/driver" "reflect" - - "github.com/go-pg/pg/types" ) var driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() -var appenderType = reflect.TypeOf((*types.ValueAppender)(nil)).Elem() +var appenderType = reflect.TypeOf((*valueAppender)(nil)).Elem() var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem() type isZeroer interface { IsZero() bool } -func isZeroFunc(typ reflect.Type) func(reflect.Value) bool { +type valueAppender interface { + AppendValue(b []byte, flags int) ([]byte, error) +} + +type Func func(reflect.Value) bool + +func Checker(typ reflect.Type) Func { if typ.Implements(isZeroerType) { - return isZero + return isZeroInterface } switch typ.Kind() { @@ -26,7 +30,7 @@ func isZeroFunc(typ reflect.Type) func(reflect.Value) bool { return isZeroBytes } return isZeroLen - case reflect.Map, reflect.Slice, reflect.String: + case reflect.String: return isZeroLen case reflect.Bool: return isZeroBool @@ -36,8 +40,8 @@ func isZeroFunc(typ reflect.Type) func(reflect.Value) bool { return isZeroUint case reflect.Float32, reflect.Float64: return isZeroFloat - case reflect.Interface, reflect.Ptr: - return isZeroNil + case reflect.Interface, reflect.Ptr, reflect.Slice, reflect.Map: + return isNil } if typ.Implements(appenderType) { @@ -50,9 +54,9 @@ func isZeroFunc(typ reflect.Type) func(reflect.Value) bool { return isZeroFalse } -func isZero(v reflect.Value) bool { - if v.Kind() == reflect.Ptr { - return v.IsNil() +func isZeroInterface(v reflect.Value) bool { + if v.Kind() == reflect.Ptr && v.IsNil() { + return true } return v.Interface().(isZeroer).IsZero() } @@ -62,8 +66,11 @@ func isZeroAppenderValue(v reflect.Value) bool { return v.IsNil() } - appender := v.Interface().(types.ValueAppender) - value := appender.AppendValue(nil, 0) + appender := v.Interface().(valueAppender) + value, err := appender.AppendValue(nil, 0) + if err != nil { + return false + } return value == nil } @@ -84,7 +91,7 @@ func isZeroLen(v reflect.Value) bool { return v.Len() == 0 } -func isZeroNil(v reflect.Value) bool { +func isNil(v reflect.Value) bool { return v.IsNil() } diff --git a/vendor/github.com/tmthrgd/go-hex/.travis.yml b/vendor/github.com/tmthrgd/go-hex/.travis.yml new file mode 100644 index 000000000..b73e2f331 --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/.travis.yml @@ -0,0 +1,11 @@ +language: go +go: + - 1.10.x + - 1.11.x + - 1.12.x + - 1.13.x + - tip +matrix: + fast_finish: true + allow_failures: + - go: tip diff --git a/vendor/github.com/tmthrgd/go-hex/LICENSE b/vendor/github.com/tmthrgd/go-hex/LICENSE new file mode 100644 index 000000000..1163cdf25 --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/LICENSE @@ -0,0 +1,82 @@ +Copyright (c) 2016, Tom Thorogood. +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 the Tom Thorogood 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 HOLDERS 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. + +---- Portions of the source code are also covered by the following license: ---- + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---- Portions of the source code are also covered by the following license: ---- + +Copyright (c) 2005-2016, Wojciech Muła +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. 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. + +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 +HOLDER 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. diff --git a/vendor/github.com/tmthrgd/go-hex/README.md b/vendor/github.com/tmthrgd/go-hex/README.md new file mode 100644 index 000000000..565411fcb --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/README.md @@ -0,0 +1,108 @@ +# go-hex + +[![GoDoc](https://godoc.org/github.com/tmthrgd/go-hex?status.svg)](https://godoc.org/github.com/tmthrgd/go-hex) +[![Build Status](https://travis-ci.org/tmthrgd/go-hex.svg?branch=master)](https://travis-ci.org/tmthrgd/go-hex) + +An efficient hexadecimal implementation for Golang. + +go-hex provides hex encoding and decoding using SSE/AVX instructions on x86-64. + +## Download + +``` +go get github.com/tmthrgd/go-hex +``` + +## Benchmark + +go-hex: +``` +BenchmarkEncode/15-8 100000000 17.4 ns/op 863.43 MB/s +BenchmarkEncode/32-8 100000000 11.9 ns/op 2690.43 MB/s +BenchmarkEncode/128-8 100000000 21.4 ns/op 5982.92 MB/s +BenchmarkEncode/1k-8 20000000 88.5 ns/op 11572.80 MB/s +BenchmarkEncode/16k-8 1000000 1254 ns/op 13058.10 MB/s +BenchmarkEncode/128k-8 100000 12965 ns/op 10109.53 MB/s +BenchmarkEncode/1M-8 10000 119465 ns/op 8777.23 MB/s +BenchmarkEncode/16M-8 500 3530380 ns/op 4752.24 MB/s +BenchmarkEncode/128M-8 50 28001913 ns/op 4793.16 MB/s +BenchmarkDecode/14-8 100000000 12.6 ns/op 1110.01 MB/s +BenchmarkDecode/32-8 100000000 12.5 ns/op 2558.10 MB/s +BenchmarkDecode/128-8 50000000 27.2 ns/op 4697.66 MB/s +BenchmarkDecode/1k-8 10000000 168 ns/op 6093.43 MB/s +BenchmarkDecode/16k-8 500000 2543 ns/op 6442.09 MB/s +BenchmarkDecode/128k-8 100000 20339 ns/op 6444.24 MB/s +BenchmarkDecode/1M-8 10000 164313 ns/op 6381.57 MB/s +BenchmarkDecode/16M-8 500 3099822 ns/op 5412.31 MB/s +BenchmarkDecode/128M-8 50 24865822 ns/op 5397.68 MB/s +``` + +[encoding/hex](https://golang.org/pkg/encoding/hex/): +``` +BenchmarkRefEncode/15-8 50000000 36.1 ns/op 415.07 MB/s +BenchmarkRefEncode/32-8 20000000 72.9 ns/op 439.14 MB/s +BenchmarkRefEncode/128-8 5000000 289 ns/op 441.54 MB/s +BenchmarkRefEncode/1k-8 1000000 2268 ns/op 451.49 MB/s +BenchmarkRefEncode/16k-8 30000 39110 ns/op 418.91 MB/s +BenchmarkRefEncode/128k-8 5000 291260 ns/op 450.02 MB/s +BenchmarkRefEncode/1M-8 1000 2277578 ns/op 460.39 MB/s +BenchmarkRefEncode/16M-8 30 37087543 ns/op 452.37 MB/s +BenchmarkRefEncode/128M-8 5 293611713 ns/op 457.13 MB/s +BenchmarkRefDecode/14-8 30000000 53.7 ns/op 260.49 MB/s +BenchmarkRefDecode/32-8 10000000 128 ns/op 248.44 MB/s +BenchmarkRefDecode/128-8 3000000 481 ns/op 265.95 MB/s +BenchmarkRefDecode/1k-8 300000 4172 ns/op 245.43 MB/s +BenchmarkRefDecode/16k-8 10000 111989 ns/op 146.30 MB/s +BenchmarkRefDecode/128k-8 2000 909077 ns/op 144.18 MB/s +BenchmarkRefDecode/1M-8 200 7275779 ns/op 144.12 MB/s +BenchmarkRefDecode/16M-8 10 116574839 ns/op 143.92 MB/s +BenchmarkRefDecode/128M-8 2 933871637 ns/op 143.72 MB/s +``` + +[encoding/hex](https://golang.org/pkg/encoding/hex/) -> go-hex: +``` +benchmark old ns/op new ns/op delta +BenchmarkEncode/15-8 36.1 17.4 -51.80% +BenchmarkEncode/32-8 72.9 11.9 -83.68% +BenchmarkEncode/128-8 289 21.4 -92.60% +BenchmarkEncode/1k-8 2268 88.5 -96.10% +BenchmarkEncode/16k-8 39110 1254 -96.79% +BenchmarkEncode/128k-8 291260 12965 -95.55% +BenchmarkEncode/1M-8 2277578 119465 -94.75% +BenchmarkEncode/16M-8 37087543 3530380 -90.48% +BenchmarkEncode/128M-8 293611713 28001913 -90.46% +BenchmarkDecode/14-8 53.7 12.6 -76.54% +BenchmarkDecode/32-8 128 12.5 -90.23% +BenchmarkDecode/128-8 481 27.2 -94.35% +BenchmarkDecode/1k-8 4172 168 -95.97% +BenchmarkDecode/16k-8 111989 2543 -97.73% +BenchmarkDecode/128k-8 909077 20339 -97.76% +BenchmarkDecode/1M-8 7275779 164313 -97.74% +BenchmarkDecode/16M-8 116574839 3099822 -97.34% +BenchmarkDecode/128M-8 933871637 24865822 -97.34% + +benchmark old MB/s new MB/s speedup +BenchmarkEncode/15-8 415.07 863.43 2.08x +BenchmarkEncode/32-8 439.14 2690.43 6.13x +BenchmarkEncode/128-8 441.54 5982.92 13.55x +BenchmarkEncode/1k-8 451.49 11572.80 25.63x +BenchmarkEncode/16k-8 418.91 13058.10 31.17x +BenchmarkEncode/128k-8 450.02 10109.53 22.46x +BenchmarkEncode/1M-8 460.39 8777.23 19.06x +BenchmarkEncode/16M-8 452.37 4752.24 10.51x +BenchmarkEncode/128M-8 457.13 4793.16 10.49x +BenchmarkDecode/14-8 260.49 1110.01 4.26x +BenchmarkDecode/32-8 248.44 2558.10 10.30x +BenchmarkDecode/128-8 265.95 4697.66 17.66x +BenchmarkDecode/1k-8 245.43 6093.43 24.83x +BenchmarkDecode/16k-8 146.30 6442.09 44.03x +BenchmarkDecode/128k-8 144.18 6444.24 44.70x +BenchmarkDecode/1M-8 144.12 6381.57 44.28x +BenchmarkDecode/16M-8 143.92 5412.31 37.61x +BenchmarkDecode/128M-8 143.72 5397.68 37.56x +``` + +## License + +Unless otherwise noted, the go-hex source files are distributed under the Modified BSD License +found in the LICENSE file. diff --git a/vendor/github.com/tmthrgd/go-hex/hex.go b/vendor/github.com/tmthrgd/go-hex/hex.go new file mode 100644 index 000000000..f4eca0e84 --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/hex.go @@ -0,0 +1,137 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. +// +// Copyright 2009 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 hex is an efficient hexadecimal implementation for Golang. +package hex + +import ( + "errors" + "fmt" +) + +var errLength = errors.New("go-hex: odd length hex string") + +var ( + lower = []byte("0123456789abcdef") + upper = []byte("0123456789ABCDEF") +) + +// InvalidByteError values describe errors resulting from an invalid byte in a hex string. +type InvalidByteError byte + +func (e InvalidByteError) Error() string { + return fmt.Sprintf("go-hex: invalid byte: %#U", rune(e)) +} + +// EncodedLen returns the length of an encoding of n source bytes. +func EncodedLen(n int) int { + return n * 2 +} + +// DecodedLen returns the length of a decoding of n source bytes. +func DecodedLen(n int) int { + return n / 2 +} + +// Encode encodes src into EncodedLen(len(src)) +// bytes of dst. As a convenience, it returns the number +// of bytes written to dst, but this value is always EncodedLen(len(src)). +// Encode implements lowercase hexadecimal encoding. +func Encode(dst, src []byte) int { + return RawEncode(dst, src, lower) +} + +// EncodeUpper encodes src into EncodedLen(len(src)) +// bytes of dst. As a convenience, it returns the number +// of bytes written to dst, but this value is always EncodedLen(len(src)). +// EncodeUpper implements uppercase hexadecimal encoding. +func EncodeUpper(dst, src []byte) int { + return RawEncode(dst, src, upper) +} + +// EncodeToString returns the lowercase hexadecimal encoding of src. +func EncodeToString(src []byte) string { + return RawEncodeToString(src, lower) +} + +// EncodeUpperToString returns the uppercase hexadecimal encoding of src. +func EncodeUpperToString(src []byte) string { + return RawEncodeToString(src, upper) +} + +// RawEncodeToString returns the hexadecimal encoding of src for a given +// alphabet. +func RawEncodeToString(src, alpha []byte) string { + dst := make([]byte, EncodedLen(len(src))) + RawEncode(dst, src, alpha) + return string(dst) +} + +// DecodeString returns the bytes represented by the hexadecimal string s. +func DecodeString(s string) ([]byte, error) { + src := []byte(s) + dst := make([]byte, DecodedLen(len(src))) + + if _, err := Decode(dst, src); err != nil { + return nil, err + } + + return dst, nil +} + +// MustDecodeString is like DecodeString but panics if the string cannot be +// parsed. It simplifies safe initialization of global variables holding +// binary data. +func MustDecodeString(str string) []byte { + dst, err := DecodeString(str) + if err != nil { + panic(err) + } + + return dst +} + +func encodeGeneric(dst, src, alpha []byte) { + for i, v := range src { + dst[i*2] = alpha[v>>4] + dst[i*2+1] = alpha[v&0x0f] + } +} + +func decodeGeneric(dst, src []byte) (uint64, bool) { + for i := 0; i < len(src)/2; i++ { + a, ok := fromHexChar(src[i*2]) + if !ok { + return uint64(i * 2), false + } + + b, ok := fromHexChar(src[i*2+1]) + if !ok { + return uint64(i*2 + 1), false + } + + dst[i] = (a << 4) | b + } + + return 0, true +} + +// fromHexChar converts a hex character into its value and a success flag. +func fromHexChar(c byte) (byte, bool) { + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + + return 0, false +} diff --git a/vendor/github.com/tmthrgd/go-hex/hex_amd64.go b/vendor/github.com/tmthrgd/go-hex/hex_amd64.go new file mode 100644 index 000000000..0f9f9a5c7 --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/hex_amd64.go @@ -0,0 +1,94 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. + +// +build amd64,!gccgo,!appengine + +package hex + +import "golang.org/x/sys/cpu" + +// RawEncode encodes src into EncodedLen(len(src)) +// bytes of dst. As a convenience, it returns the number +// of bytes written to dst, but this value is always EncodedLen(len(src)). +// RawEncode implements hexadecimal encoding for a given alphabet. +func RawEncode(dst, src, alpha []byte) int { + if len(alpha) != 16 { + panic("invalid alphabet") + } + + if len(dst) < len(src)*2 { + panic("dst buffer is too small") + } + + if len(src) == 0 { + return 0 + } + + switch { + case cpu.X86.HasAVX: + encodeAVX(&dst[0], &src[0], uint64(len(src)), &alpha[0]) + case cpu.X86.HasSSE41: + encodeSSE(&dst[0], &src[0], uint64(len(src)), &alpha[0]) + default: + encodeGeneric(dst, src, alpha) + } + + return len(src) * 2 +} + +// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual +// number of bytes written to dst. +// +// If Decode encounters invalid input, it returns an error describing the failure. +func Decode(dst, src []byte) (int, error) { + if len(src)%2 != 0 { + return 0, errLength + } + + if len(dst) < len(src)/2 { + panic("dst buffer is too small") + } + + if len(src) == 0 { + return 0, nil + } + + var ( + n uint64 + ok bool + ) + switch { + case cpu.X86.HasAVX: + n, ok = decodeAVX(&dst[0], &src[0], uint64(len(src))) + case cpu.X86.HasSSE41: + n, ok = decodeSSE(&dst[0], &src[0], uint64(len(src))) + default: + n, ok = decodeGeneric(dst, src) + } + + if !ok { + return 0, InvalidByteError(src[n]) + } + + return len(src) / 2, nil +} + +//go:generate go run asm_gen.go + +// This function is implemented in hex_encode_amd64.s +//go:noescape +func encodeAVX(dst *byte, src *byte, len uint64, alpha *byte) + +// This function is implemented in hex_encode_amd64.s +//go:noescape +func encodeSSE(dst *byte, src *byte, len uint64, alpha *byte) + +// This function is implemented in hex_decode_amd64.s +//go:noescape +func decodeAVX(dst *byte, src *byte, len uint64) (n uint64, ok bool) + +// This function is implemented in hex_decode_amd64.s +//go:noescape +func decodeSSE(dst *byte, src *byte, len uint64) (n uint64, ok bool) diff --git a/vendor/github.com/tmthrgd/go-hex/hex_decode_amd64.s b/vendor/github.com/tmthrgd/go-hex/hex_decode_amd64.s new file mode 100644 index 000000000..25d9cefb1 --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/hex_decode_amd64.s @@ -0,0 +1,303 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. +// +// Copyright 2005-2016, Wojciech Muła. All rights reserved. +// Use of this source code is governed by a +// Simplified BSD License license that can be found in +// the LICENSE file. +// +// This file is auto-generated - do not modify + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA decodeBase<>+0x00(SB)/8, $0x3030303030303030 +DATA decodeBase<>+0x08(SB)/8, $0x3030303030303030 +DATA decodeBase<>+0x10(SB)/8, $0x2727272727272727 +DATA decodeBase<>+0x18(SB)/8, $0x2727272727272727 +GLOBL decodeBase<>(SB),RODATA,$32 + +DATA decodeToLower<>+0x00(SB)/8, $0x2020202020202020 +DATA decodeToLower<>+0x08(SB)/8, $0x2020202020202020 +GLOBL decodeToLower<>(SB),RODATA,$16 + +DATA decodeHigh<>+0x00(SB)/8, $0x0e0c0a0806040200 +DATA decodeHigh<>+0x08(SB)/8, $0xffffffffffffffff +GLOBL decodeHigh<>(SB),RODATA,$16 + +DATA decodeLow<>+0x00(SB)/8, $0x0f0d0b0907050301 +DATA decodeLow<>+0x08(SB)/8, $0xffffffffffffffff +GLOBL decodeLow<>(SB),RODATA,$16 + +DATA decodeValid<>+0x00(SB)/8, $0xb0b0b0b0b0b0b0b0 +DATA decodeValid<>+0x08(SB)/8, $0xb0b0b0b0b0b0b0b0 +DATA decodeValid<>+0x10(SB)/8, $0xb9b9b9b9b9b9b9b9 +DATA decodeValid<>+0x18(SB)/8, $0xb9b9b9b9b9b9b9b9 +DATA decodeValid<>+0x20(SB)/8, $0xe1e1e1e1e1e1e1e1 +DATA decodeValid<>+0x28(SB)/8, $0xe1e1e1e1e1e1e1e1 +DATA decodeValid<>+0x30(SB)/8, $0xe6e6e6e6e6e6e6e6 +DATA decodeValid<>+0x38(SB)/8, $0xe6e6e6e6e6e6e6e6 +GLOBL decodeValid<>(SB),RODATA,$64 + +DATA decodeToSigned<>+0x00(SB)/8, $0x8080808080808080 +DATA decodeToSigned<>+0x08(SB)/8, $0x8080808080808080 +GLOBL decodeToSigned<>(SB),RODATA,$16 + +TEXT ·decodeAVX(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ SI, R15 + MOVOU decodeValid<>(SB), X14 + MOVOU decodeValid<>+0x20(SB), X15 + MOVW $65535, DX + CMPQ BX, $16 + JB tail +bigloop: + MOVOU (SI), X0 + VPXOR decodeToSigned<>(SB), X0, X1 + POR decodeToLower<>(SB), X0 + VPXOR decodeToSigned<>(SB), X0, X2 + VPCMPGTB X1, X14, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + VPCMPGTB X2, X15, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + VPSHUFB decodeLow<>(SB), X0, X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + MOVQ X0, (DI) + SUBQ $16, BX + JZ ret + ADDQ $16, SI + ADDQ $8, DI + CMPQ BX, $16 + JAE bigloop +tail: + MOVQ $16, CX + SUBQ BX, CX + SHRW CX, DX + CMPQ BX, $4 + JB tail_in_2 + JE tail_in_4 + CMPQ BX, $8 + JB tail_in_6 + JE tail_in_8 + CMPQ BX, $12 + JB tail_in_10 + JE tail_in_12 +tail_in_14: + PINSRW $6, 12(SI), X0 +tail_in_12: + PINSRW $5, 10(SI), X0 +tail_in_10: + PINSRW $4, 8(SI), X0 +tail_in_8: + PINSRQ $0, (SI), X0 + JMP tail_conv +tail_in_6: + PINSRW $2, 4(SI), X0 +tail_in_4: + PINSRW $1, 2(SI), X0 +tail_in_2: + PINSRW $0, (SI), X0 +tail_conv: + VPXOR decodeToSigned<>(SB), X0, X1 + POR decodeToLower<>(SB), X0 + VPXOR decodeToSigned<>(SB), X0, X2 + VPCMPGTB X1, X14, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + VPCMPGTB X2, X15, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + VPSHUFB decodeLow<>(SB), X0, X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + CMPQ BX, $4 + JB tail_out_2 + JE tail_out_4 + CMPQ BX, $8 + JB tail_out_6 + JE tail_out_8 + CMPQ BX, $12 + JB tail_out_10 + JE tail_out_12 +tail_out_14: + PEXTRB $6, X0, 6(DI) +tail_out_12: + PEXTRB $5, X0, 5(DI) +tail_out_10: + PEXTRB $4, X0, 4(DI) +tail_out_8: + MOVL X0, (DI) + JMP ret +tail_out_6: + PEXTRB $2, X0, 2(DI) +tail_out_4: + PEXTRB $1, X0, 1(DI) +tail_out_2: + PEXTRB $0, X0, (DI) +ret: + MOVB $1, ok+32(FP) + RET +invalid: + BSFW AX, AX + SUBQ R15, SI + ADDQ SI, AX + MOVQ AX, n+24(FP) + MOVB $0, ok+32(FP) + RET + +TEXT ·decodeSSE(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ SI, R15 + MOVOU decodeValid<>(SB), X14 + MOVOU decodeValid<>+0x20(SB), X15 + MOVW $65535, DX + CMPQ BX, $16 + JB tail +bigloop: + MOVOU (SI), X0 + MOVOU X0, X1 + PXOR decodeToSigned<>(SB), X1 + POR decodeToLower<>(SB), X0 + MOVOU X0, X2 + PXOR decodeToSigned<>(SB), X2 + MOVOU X14, X3 + PCMPGTB X1, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + MOVOU X15, X4 + PCMPGTB X2, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + MOVOU X0, X3 + PSHUFB decodeLow<>(SB), X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + MOVQ X0, (DI) + SUBQ $16, BX + JZ ret + ADDQ $16, SI + ADDQ $8, DI + CMPQ BX, $16 + JAE bigloop +tail: + MOVQ $16, CX + SUBQ BX, CX + SHRW CX, DX + CMPQ BX, $4 + JB tail_in_2 + JE tail_in_4 + CMPQ BX, $8 + JB tail_in_6 + JE tail_in_8 + CMPQ BX, $12 + JB tail_in_10 + JE tail_in_12 +tail_in_14: + PINSRW $6, 12(SI), X0 +tail_in_12: + PINSRW $5, 10(SI), X0 +tail_in_10: + PINSRW $4, 8(SI), X0 +tail_in_8: + PINSRQ $0, (SI), X0 + JMP tail_conv +tail_in_6: + PINSRW $2, 4(SI), X0 +tail_in_4: + PINSRW $1, 2(SI), X0 +tail_in_2: + PINSRW $0, (SI), X0 +tail_conv: + MOVOU X0, X1 + PXOR decodeToSigned<>(SB), X1 + POR decodeToLower<>(SB), X0 + MOVOU X0, X2 + PXOR decodeToSigned<>(SB), X2 + MOVOU X14, X3 + PCMPGTB X1, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + MOVOU X15, X4 + PCMPGTB X2, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + MOVOU X0, X3 + PSHUFB decodeLow<>(SB), X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + CMPQ BX, $4 + JB tail_out_2 + JE tail_out_4 + CMPQ BX, $8 + JB tail_out_6 + JE tail_out_8 + CMPQ BX, $12 + JB tail_out_10 + JE tail_out_12 +tail_out_14: + PEXTRB $6, X0, 6(DI) +tail_out_12: + PEXTRB $5, X0, 5(DI) +tail_out_10: + PEXTRB $4, X0, 4(DI) +tail_out_8: + MOVL X0, (DI) + JMP ret +tail_out_6: + PEXTRB $2, X0, 2(DI) +tail_out_4: + PEXTRB $1, X0, 1(DI) +tail_out_2: + PEXTRB $0, X0, (DI) +ret: + MOVB $1, ok+32(FP) + RET +invalid: + BSFW AX, AX + SUBQ R15, SI + ADDQ SI, AX + MOVQ AX, n+24(FP) + MOVB $0, ok+32(FP) + RET diff --git a/vendor/github.com/tmthrgd/go-hex/hex_encode_amd64.s b/vendor/github.com/tmthrgd/go-hex/hex_encode_amd64.s new file mode 100644 index 000000000..96e6e4caa --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/hex_encode_amd64.s @@ -0,0 +1,227 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. +// +// Copyright 2005-2016, Wojciech Muła. All rights reserved. +// Use of this source code is governed by a +// Simplified BSD License license that can be found in +// the LICENSE file. +// +// This file is auto-generated - do not modify + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA encodeMask<>+0x00(SB)/8, $0x0f0f0f0f0f0f0f0f +DATA encodeMask<>+0x08(SB)/8, $0x0f0f0f0f0f0f0f0f +GLOBL encodeMask<>(SB),RODATA,$16 + +TEXT ·encodeAVX(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ alpha+24(FP), DX + MOVOU (DX), X15 + CMPQ BX, $16 + JB tail +bigloop: + MOVOU -16(SI)(BX*1), X0 + VPAND encodeMask<>(SB), X0, X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + VPUNPCKHBW X1, X0, X3 + PUNPCKLBW X1, X0 + VPSHUFB X0, X15, X1 + VPSHUFB X3, X15, X2 + MOVOU X2, -16(DI)(BX*2) + MOVOU X1, -32(DI)(BX*2) + SUBQ $16, BX + JZ ret + CMPQ BX, $16 + JAE bigloop +tail: + CMPQ BX, $2 + JB tail_in_1 + JE tail_in_2 + CMPQ BX, $4 + JB tail_in_3 + JE tail_in_4 + CMPQ BX, $6 + JB tail_in_5 + JE tail_in_6 + CMPQ BX, $8 + JB tail_in_7 +tail_in_8: + MOVQ (SI), X0 + JMP tail_conv +tail_in_7: + PINSRB $6, 6(SI), X0 +tail_in_6: + PINSRB $5, 5(SI), X0 +tail_in_5: + PINSRB $4, 4(SI), X0 +tail_in_4: + PINSRD $0, (SI), X0 + JMP tail_conv +tail_in_3: + PINSRB $2, 2(SI), X0 +tail_in_2: + PINSRB $1, 1(SI), X0 +tail_in_1: + PINSRB $0, (SI), X0 +tail_conv: + VPAND encodeMask<>(SB), X0, X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + PUNPCKLBW X1, X0 + VPSHUFB X0, X15, X1 + CMPQ BX, $2 + JB tail_out_1 + JE tail_out_2 + CMPQ BX, $4 + JB tail_out_3 + JE tail_out_4 + CMPQ BX, $6 + JB tail_out_5 + JE tail_out_6 + CMPQ BX, $8 + JB tail_out_7 +tail_out_8: + MOVOU X1, (DI) + SUBQ $8, BX + JZ ret + ADDQ $8, SI + ADDQ $16, DI + JMP tail +tail_out_7: + PEXTRB $13, X1, 13(DI) + PEXTRB $12, X1, 12(DI) +tail_out_6: + PEXTRB $11, X1, 11(DI) + PEXTRB $10, X1, 10(DI) +tail_out_5: + PEXTRB $9, X1, 9(DI) + PEXTRB $8, X1, 8(DI) +tail_out_4: + MOVQ X1, (DI) + RET +tail_out_3: + PEXTRB $5, X1, 5(DI) + PEXTRB $4, X1, 4(DI) +tail_out_2: + PEXTRB $3, X1, 3(DI) + PEXTRB $2, X1, 2(DI) +tail_out_1: + PEXTRB $1, X1, 1(DI) + PEXTRB $0, X1, (DI) +ret: + RET + +TEXT ·encodeSSE(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ alpha+24(FP), DX + MOVOU (DX), X15 + CMPQ BX, $16 + JB tail +bigloop: + MOVOU -16(SI)(BX*1), X0 + MOVOU X0, X1 + PAND encodeMask<>(SB), X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + MOVOU X0, X3 + PUNPCKHBW X1, X3 + PUNPCKLBW X1, X0 + MOVOU X15, X1 + PSHUFB X0, X1 + MOVOU X15, X2 + PSHUFB X3, X2 + MOVOU X2, -16(DI)(BX*2) + MOVOU X1, -32(DI)(BX*2) + SUBQ $16, BX + JZ ret + CMPQ BX, $16 + JAE bigloop +tail: + CMPQ BX, $2 + JB tail_in_1 + JE tail_in_2 + CMPQ BX, $4 + JB tail_in_3 + JE tail_in_4 + CMPQ BX, $6 + JB tail_in_5 + JE tail_in_6 + CMPQ BX, $8 + JB tail_in_7 +tail_in_8: + MOVQ (SI), X0 + JMP tail_conv +tail_in_7: + PINSRB $6, 6(SI), X0 +tail_in_6: + PINSRB $5, 5(SI), X0 +tail_in_5: + PINSRB $4, 4(SI), X0 +tail_in_4: + PINSRD $0, (SI), X0 + JMP tail_conv +tail_in_3: + PINSRB $2, 2(SI), X0 +tail_in_2: + PINSRB $1, 1(SI), X0 +tail_in_1: + PINSRB $0, (SI), X0 +tail_conv: + MOVOU X0, X1 + PAND encodeMask<>(SB), X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + PUNPCKLBW X1, X0 + MOVOU X15, X1 + PSHUFB X0, X1 + CMPQ BX, $2 + JB tail_out_1 + JE tail_out_2 + CMPQ BX, $4 + JB tail_out_3 + JE tail_out_4 + CMPQ BX, $6 + JB tail_out_5 + JE tail_out_6 + CMPQ BX, $8 + JB tail_out_7 +tail_out_8: + MOVOU X1, (DI) + SUBQ $8, BX + JZ ret + ADDQ $8, SI + ADDQ $16, DI + JMP tail +tail_out_7: + PEXTRB $13, X1, 13(DI) + PEXTRB $12, X1, 12(DI) +tail_out_6: + PEXTRB $11, X1, 11(DI) + PEXTRB $10, X1, 10(DI) +tail_out_5: + PEXTRB $9, X1, 9(DI) + PEXTRB $8, X1, 8(DI) +tail_out_4: + MOVQ X1, (DI) + RET +tail_out_3: + PEXTRB $5, X1, 5(DI) + PEXTRB $4, X1, 4(DI) +tail_out_2: + PEXTRB $3, X1, 3(DI) + PEXTRB $2, X1, 2(DI) +tail_out_1: + PEXTRB $1, X1, 1(DI) + PEXTRB $0, X1, (DI) +ret: + RET diff --git a/vendor/github.com/tmthrgd/go-hex/hex_other.go b/vendor/github.com/tmthrgd/go-hex/hex_other.go new file mode 100644 index 000000000..fab232186 --- /dev/null +++ b/vendor/github.com/tmthrgd/go-hex/hex_other.go @@ -0,0 +1,36 @@ +// Copyright 2009 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 !amd64 gccgo appengine + +package hex + +// RawEncode encodes src into EncodedLen(len(src)) +// bytes of dst. As a convenience, it returns the number +// of bytes written to dst, but this value is always EncodedLen(len(src)). +// RawEncode implements hexadecimal encoding for a given alphabet. +func RawEncode(dst, src, alpha []byte) int { + if len(alpha) != 16 { + panic("invalid alphabet") + } + + encodeGeneric(dst, src, alpha) + return len(src) * 2 +} + +// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual +// number of bytes written to dst. +// +// If Decode encounters invalid input, it returns an error describing the failure. +func Decode(dst, src []byte) (int, error) { + if len(src)%2 == 1 { + return 0, errLength + } + + if n, ok := decodeGeneric(dst, src); !ok { + return 0, InvalidByteError(src[n]) + } + + return len(src) / 2, nil +} diff --git a/vendor/github.com/vmihailenco/bufpool/.travis.yml b/vendor/github.com/vmihailenco/bufpool/.travis.yml new file mode 100644 index 000000000..c7383a2b1 --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/.travis.yml @@ -0,0 +1,20 @@ +sudo: false +language: go + +go: + - 1.11.x + - 1.12.x + - 1.13.x + - tip + +matrix: + allow_failures: + - go: tip + +env: + - GO111MODULE=on + +go_import_path: github.com/vmihailenco/bufpool + +before_install: + - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.21.0 diff --git a/vendor/github.com/vmihailenco/bufpool/LICENSE b/vendor/github.com/vmihailenco/bufpool/LICENSE new file mode 100644 index 000000000..2b76a892e --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2014 Juan Batiz-Benet +Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia +Copyright (c) 2019 Vladimir Mihailenco + +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. diff --git a/vendor/github.com/go-pg/pg/Makefile b/vendor/github.com/vmihailenco/bufpool/Makefile similarity index 58% rename from vendor/github.com/go-pg/pg/Makefile rename to vendor/github.com/vmihailenco/bufpool/Makefile index 5c67b332a..57914e333 100644 --- a/vendor/github.com/go-pg/pg/Makefile +++ b/vendor/github.com/vmihailenco/bufpool/Makefile @@ -1,5 +1,6 @@ all: go test ./... go test ./... -short -race + go test ./... -run=NONE -bench=. -benchmem env GOOS=linux GOARCH=386 go test ./... - go vet ./... + golangci-lint run diff --git a/vendor/github.com/vmihailenco/bufpool/README.md b/vendor/github.com/vmihailenco/bufpool/README.md new file mode 100644 index 000000000..05a70791c --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/README.md @@ -0,0 +1,74 @@ +# bufpool + +[![Build Status](https://travis-ci.org/vmihailenco/bufpool.svg)](https://travis-ci.org/vmihailenco/bufpool) +[![GoDoc](https://godoc.org/github.com/vmihailenco/bufpool?status.svg)](https://godoc.org/github.com/vmihailenco/bufpool) + +bufpool is an implementation of a pool of byte buffers with anti-memory-waste protection. It is based on the code and ideas from these 2 projects: +- https://github.com/libp2p/go-buffer-pool +- https://github.com/valyala/bytebufferpool + +bufpool consists of global pool of buffers that have a capacity of a power of 2 starting from 64 bytes to 32 megabytes. It also provides individual pools that maintain usage stats to provide buffers of the size that satisfies 95% of the calls. Global pool is used to reuse buffers between different parts of the app. + +# Installation + +``` go +go get github.com/vmihailenco/bufpool +``` + +# Usage + +bufpool can be used as a replacement for `sync.Pool`: + +``` go +var jsonPool bufpool.Pool // basically sync.Pool with usage stats + +func writeJSON(w io.Writer, obj interface{}) error { + buf := jsonPool.Get() + defer jsonPool.Put(buf) + + if err := json.NewEncoder(buf).Encode(obj); err != nil { + return err + } + + _, err := w.Write(buf.Bytes()) + return err +} +``` + +or to allocate buffer of the given size: + +``` go +func writeHex(w io.Writer, data []byte) error { + n := hex.EncodedLen(len(data))) + + buf := bufpool.Get(n) // buf.Len() is guaranteed to equal n + defer bufpool.Put(buf) + + tmp := buf.Bytes() + hex.Encode(tmp, data) + + _, err := w.Write(tmp) + return err +} +``` + +If you need to append data to the buffer you can use following pattern: + +``` go +buf := bufpool.Get(n) +defer bufpool.Put(buf) + +bb := buf.Bytes()[:0] + +bb = append(bb, ...) + +buf.ResetBuf(bb) +``` + +You can also change default pool thresholds: + +``` go +var jsonPool = bufpool.Pool{ + ServePctile: 0.95, // serve p95 buffers +} +``` diff --git a/vendor/github.com/vmihailenco/bufpool/buf_pool.go b/vendor/github.com/vmihailenco/bufpool/buf_pool.go new file mode 100644 index 000000000..2daa69888 --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/buf_pool.go @@ -0,0 +1,67 @@ +package bufpool + +import ( + "log" + "sync" +) + +var thePool bufPool + +// Get retrieves a buffer of the appropriate length from the buffer pool or +// allocates a new one. Get may choose to ignore the pool and treat it as empty. +// Callers should not assume any relation between values passed to Put and the +// values returned by Get. +// +// If no suitable buffer exists in the pool, Get creates one. +func Get(length int) *Buffer { + return thePool.Get(length) +} + +// Put returns a buffer to the buffer pool. +func Put(buf *Buffer) { + thePool.Put(buf) +} + +type bufPool struct { + pools [steps]sync.Pool +} + +func (p *bufPool) Get(length int) *Buffer { + if length > maxPoolSize { + return NewBuffer(make([]byte, length)) + } + + idx := index(length) + if bufIface := p.pools[idx].Get(); bufIface != nil { + buf := bufIface.(*Buffer) + unlock(buf) + if length > buf.Cap() { + log.Println(idx, buf.Len(), buf.Cap(), buf.String()) + } + buf.buf = buf.buf[:length] + return buf + } + + b := make([]byte, length, indexSize(idx)) + return NewBuffer(b) +} + +func (p *bufPool) Put(buf *Buffer) { + length := buf.Cap() + if length > maxPoolSize || length < minSize { + return // drop it + } + + idx := prevIndex(length) + lock(buf) + p.pools[idx].Put(buf) +} + +func lock(buf *Buffer) { + buf.buf = buf.buf[:cap(buf.buf)] + buf.off = cap(buf.buf) + 1 +} + +func unlock(buf *Buffer) { + buf.off = 0 +} diff --git a/vendor/github.com/vmihailenco/bufpool/buffer.go b/vendor/github.com/vmihailenco/bufpool/buffer.go new file mode 100644 index 000000000..a061a0b70 --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/buffer.go @@ -0,0 +1,397 @@ +// Copyright 2009 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 bufpool + +// Simple byte buffer for marshaling data. + +import ( + "bytes" + "errors" + "io" + "unicode/utf8" +) + +// smallBufferSize is an initial allocation minimal capacity. +const smallBufferSize = 64 + +// A Buffer is a variable-sized buffer of bytes with Read and Write methods. +// The zero value for Buffer is an empty buffer ready to use. +type Buffer struct { + buf []byte // contents are the bytes buf[off : len(buf)] + off int // read at &buf[off], write at &buf[len(buf)] + lastRead readOp // last read operation, so that Unread* can work correctly. +} + +// The readOp constants describe the last action performed on +// the buffer, so that UnreadRune and UnreadByte can check for +// invalid usage. opReadRuneX constants are chosen such that +// converted to int they correspond to the rune size that was read. +type readOp int8 + +// Don't use iota for these, as the values need to correspond with the +// names and comments, which is easier to see when being explicit. +const ( + opRead readOp = -1 // Any other read operation. + opInvalid readOp = 0 // Non-read operation. + opReadRune1 readOp = 1 // Read rune of size 1. +) + +var errNegativeRead = errors.New("bytes.Buffer: reader returned negative count from Read") + +const maxInt = int(^uint(0) >> 1) + +// Bytes returns a slice of length b.Len() holding the unread portion of the buffer. +// The slice is valid for use only until the next buffer modification (that is, +// only until the next call to a method like Read, Write, Reset, or Truncate). +// The slice aliases the buffer content at least until the next buffer modification, +// so immediate changes to the slice will affect the result of future reads. +func (b *Buffer) Bytes() []byte { return b.buf[b.off:] } + +// String returns the contents of the unread portion of the buffer +// as a string. If the Buffer is a nil pointer, it returns "". +// +// To build strings more efficiently, see the strings.Builder type. +func (b *Buffer) String() string { + if b == nil { + // Special case, useful in debugging. + return "" + } + return string(b.buf[b.off:]) +} + +// empty reports whether the unread portion of the buffer is empty. +func (b *Buffer) empty() bool { return len(b.buf) <= b.off } + +// Len returns the number of bytes of the unread portion of the buffer; +// b.Len() == len(b.Bytes()). +func (b *Buffer) Len() int { return len(b.buf) - b.off } + +// Cap returns the capacity of the buffer's underlying byte slice, that is, the +// total space allocated for the buffer's data. +func (b *Buffer) Cap() int { return cap(b.buf) } + +// Truncate discards all but the first n unread bytes from the buffer +// but continues to use the same allocated storage. +// It panics if n is negative or greater than the length of the buffer. +func (b *Buffer) Truncate(n int) { + if n == 0 { + b.Reset() + return + } + b.lastRead = opInvalid + if n < 0 || n > b.Len() { + panic("bytes.Buffer: truncation out of range") + } + b.buf = b.buf[:b.off+n] +} + +// tryGrowByReslice is a inlineable version of grow for the fast-case where the +// internal buffer only needs to be resliced. +// It returns the index where bytes should be written and whether it succeeded. +func (b *Buffer) tryGrowByReslice(n int) (int, bool) { + if l := len(b.buf); n <= cap(b.buf)-l { + b.buf = b.buf[:l+n] + return l, true + } + return 0, false +} + +// Grow grows the buffer's capacity, if necessary, to guarantee space for +// another n bytes. After Grow(n), at least n bytes can be written to the +// buffer without another allocation. +// If n is negative, Grow will panic. +// If the buffer can't grow it will panic with ErrTooLarge. +func (b *Buffer) Grow(n int) { + if n < 0 { + panic("bytes.Buffer.Grow: negative count") + } + m := b.grow(n) + b.buf = b.buf[:m] +} + +// Write appends the contents of p to the buffer, growing the buffer as +// needed. The return value n is the length of p; err is always nil. If the +// buffer becomes too large, Write will panic with ErrTooLarge. +func (b *Buffer) Write(p []byte) (n int, err error) { + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(len(p)) + if !ok { + m = b.grow(len(p)) + } + return copy(b.buf[m:], p), nil +} + +// WriteString appends the contents of s to the buffer, growing the buffer as +// needed. The return value n is the length of s; err is always nil. If the +// buffer becomes too large, WriteString will panic with ErrTooLarge. +func (b *Buffer) WriteString(s string) (n int, err error) { + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(len(s)) + if !ok { + m = b.grow(len(s)) + } + return copy(b.buf[m:], s), nil +} + +// MinRead is the minimum slice size passed to a Read call by +// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond +// what is required to hold the contents of r, ReadFrom will not grow the +// underlying buffer. +const minRead = 512 + +// ReadFrom reads data from r until EOF and appends it to the buffer, growing +// the buffer as needed. The return value n is the number of bytes read. Any +// error except io.EOF encountered during the read is also returned. If the +// buffer becomes too large, ReadFrom will panic with ErrTooLarge. +func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { + b.lastRead = opInvalid + for { + i := b.grow(minRead) + b.buf = b.buf[:i] + m, e := r.Read(b.buf[i:cap(b.buf)]) + if m < 0 { + panic(errNegativeRead) + } + + b.buf = b.buf[:i+m] + n += int64(m) + if e == io.EOF { + return n, nil // e is EOF, so return nil explicitly + } + if e != nil { + return n, e + } + } +} + +// WriteTo writes data to w until the buffer is drained or an error occurs. +// The return value n is the number of bytes written; it always fits into an +// int, but it is int64 to match the io.WriterTo interface. Any error +// encountered during the write is also returned. +func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { + b.lastRead = opInvalid + if nBytes := b.Len(); nBytes > 0 { + m, e := w.Write(b.buf[b.off:]) + if m > nBytes { + panic("bytes.Buffer.WriteTo: invalid Write count") + } + b.off += m + n = int64(m) + if e != nil { + return n, e + } + // all bytes should have been written, by definition of + // Write method in io.Writer + if m != nBytes { + return n, io.ErrShortWrite + } + } + // Buffer is now empty; reset. + b.Reset() + return n, nil +} + +// WriteByte appends the byte c to the buffer, growing the buffer as needed. +// The returned error is always nil, but is included to match bufio.Writer's +// WriteByte. If the buffer becomes too large, WriteByte will panic with +// ErrTooLarge. +func (b *Buffer) WriteByte(c byte) error { + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(1) + if !ok { + m = b.grow(1) + } + b.buf[m] = c + return nil +} + +// WriteRune appends the UTF-8 encoding of Unicode code point r to the +// buffer, returning its length and an error, which is always nil but is +// included to match bufio.Writer's WriteRune. The buffer is grown as needed; +// if it becomes too large, WriteRune will panic with ErrTooLarge. +func (b *Buffer) WriteRune(r rune) (n int, err error) { + if r < utf8.RuneSelf { + _ = b.WriteByte(byte(r)) + return 1, nil + } + b.lastRead = opInvalid + m, ok := b.tryGrowByReslice(utf8.UTFMax) + if !ok { + m = b.grow(utf8.UTFMax) + } + n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r) + b.buf = b.buf[:m+n] + return n, nil +} + +// Read reads the next len(p) bytes from the buffer or until the buffer +// is drained. The return value n is the number of bytes read. If the +// buffer has no data to return, err is io.EOF (unless len(p) is zero); +// otherwise it is nil. +func (b *Buffer) Read(p []byte) (n int, err error) { + b.lastRead = opInvalid + if b.empty() { + // Buffer is empty, reset to recover space. + b.Reset() + if len(p) == 0 { + return 0, nil + } + return 0, io.EOF + } + n = copy(p, b.buf[b.off:]) + b.off += n + if n > 0 { + b.lastRead = opRead + } + return n, nil +} + +// Next returns a slice containing the next n bytes from the buffer, +// advancing the buffer as if the bytes had been returned by Read. +// If there are fewer than n bytes in the buffer, Next returns the entire buffer. +// The slice is only valid until the next call to a read or write method. +func (b *Buffer) Next(n int) []byte { + b.lastRead = opInvalid + m := b.Len() + if n > m { + n = m + } + data := b.buf[b.off : b.off+n] + b.off += n + if n > 0 { + b.lastRead = opRead + } + return data +} + +// ReadByte reads and returns the next byte from the buffer. +// If no byte is available, it returns error io.EOF. +func (b *Buffer) ReadByte() (byte, error) { + if b.empty() { + // Buffer is empty, reset to recover space. + b.Reset() + return 0, io.EOF + } + c := b.buf[b.off] + b.off++ + b.lastRead = opRead + return c, nil +} + +// ReadRune reads and returns the next UTF-8-encoded +// Unicode code point from the buffer. +// If no bytes are available, the error returned is io.EOF. +// If the bytes are an erroneous UTF-8 encoding, it +// consumes one byte and returns U+FFFD, 1. +func (b *Buffer) ReadRune() (r rune, size int, err error) { + if b.empty() { + // Buffer is empty, reset to recover space. + b.Reset() + return 0, 0, io.EOF + } + c := b.buf[b.off] + if c < utf8.RuneSelf { + b.off++ + b.lastRead = opReadRune1 + return rune(c), 1, nil + } + r, n := utf8.DecodeRune(b.buf[b.off:]) + b.off += n + b.lastRead = readOp(n) + return r, n, nil +} + +// UnreadRune unreads the last rune returned by ReadRune. +// If the most recent read or write operation on the buffer was +// not a successful ReadRune, UnreadRune returns an error. (In this regard +// it is stricter than UnreadByte, which will unread the last byte +// from any read operation.) +func (b *Buffer) UnreadRune() error { + if b.lastRead <= opInvalid { + return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune") + } + if b.off >= int(b.lastRead) { + b.off -= int(b.lastRead) + } + b.lastRead = opInvalid + return nil +} + +var errUnreadByte = errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read") + +// UnreadByte unreads the last byte returned by the most recent successful +// read operation that read at least one byte. If a write has happened since +// the last read, if the last read returned an error, or if the read read zero +// bytes, UnreadByte returns an error. +func (b *Buffer) UnreadByte() error { + if b.lastRead == opInvalid { + return errUnreadByte + } + b.lastRead = opInvalid + if b.off > 0 { + b.off-- + } + return nil +} + +// ReadBytes reads until the first occurrence of delim in the input, +// returning a slice containing the data up to and including the delimiter. +// If ReadBytes encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often io.EOF). +// ReadBytes returns err != nil if and only if the returned data does not end in +// delim. +func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) { + slice, err := b.readSlice(delim) + // return a copy of slice. The buffer's backing array may + // be overwritten by later calls. + line = append(line, slice...) + return line, err +} + +// readSlice is like ReadBytes but returns a reference to internal buffer data. +func (b *Buffer) readSlice(delim byte) (line []byte, err error) { + i := bytes.IndexByte(b.buf[b.off:], delim) + end := b.off + i + 1 + if i < 0 { + end = len(b.buf) + err = io.EOF + } + line = b.buf[b.off:end] + b.off = end + b.lastRead = opRead + return line, err +} + +// ReadString reads until the first occurrence of delim in the input, +// returning a string containing the data up to and including the delimiter. +// If ReadString encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often io.EOF). +// ReadString returns err != nil if and only if the returned data does not end +// in delim. +func (b *Buffer) ReadString(delim byte) (line string, err error) { + slice, err := b.readSlice(delim) + return string(slice), err +} + +// NewBuffer creates and initializes a new Buffer using buf as its +// initial contents. The new Buffer takes ownership of buf, and the +// caller should not use buf after this call. NewBuffer is intended to +// prepare a Buffer to read existing data. It can also be used to set +// the initial size of the internal buffer for writing. To do that, +// buf should have the desired capacity but a length of zero. +// +// In most cases, new(Buffer) (or just declaring a Buffer variable) is +// sufficient to initialize a Buffer. +func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } + +// NewBufferString creates and initializes a new Buffer using string s as its +// initial contents. It is intended to prepare a buffer to read an existing +// string. +// +// In most cases, new(Buffer) (or just declaring a Buffer variable) is +// sufficient to initialize a Buffer. +func NewBufferString(s string) *Buffer { + return &Buffer{buf: []byte(s)} +} diff --git a/vendor/github.com/vmihailenco/bufpool/buffer_ext.go b/vendor/github.com/vmihailenco/bufpool/buffer_ext.go new file mode 100644 index 000000000..8a904bc5c --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/buffer_ext.go @@ -0,0 +1,66 @@ +package bufpool + +import "bytes" + +// Reset resets the buffer to be empty, +// but it retains the underlying storage for use by future writes. +// Reset is the same as Truncate(0). +func (b *Buffer) Reset() { + if b.off > cap(b.buf) { + panic("Buffer is used after Put") + } + b.buf = b.buf[:0] + b.off = 0 + b.lastRead = opInvalid +} + +func (b *Buffer) ResetBuf(buf []byte) { + if b.off > cap(b.buf) { + panic("Buffer is used after Put") + } + b.buf = buf[:0] + b.off = 0 + b.lastRead = opInvalid +} + +// grow grows the buffer to guarantee space for n more bytes. +// It returns the index where bytes should be written. +// If the buffer can't grow it will panic with ErrTooLarge. +func (b *Buffer) grow(n int) int { + if b.off > cap(b.buf) { + panic("Buffer is used after Put") + } + m := b.Len() + // If buffer is empty, reset to recover space. + if m == 0 && b.off != 0 { + b.Reset() + } + // Try to grow by means of a reslice. + if i, ok := b.tryGrowByReslice(n); ok { + return i + } + if b.buf == nil && n <= smallBufferSize { + b.buf = make([]byte, n, smallBufferSize) + return 0 + } + c := cap(b.buf) + if n <= c/2-m { + // We can slide things down instead of allocating a new + // slice. We only need m+n <= c to slide, but + // we instead let capacity get twice as large so we + // don't spend all our time copying. + copy(b.buf, b.buf[b.off:]) + } else if c > maxInt-c-n { + panic(bytes.ErrTooLarge) + } else { + // Not enough space anywhere, we need to allocate. + tmp := Get(2*c + n) + copy(tmp.buf, b.buf[b.off:]) + b.buf, tmp.buf = tmp.buf, b.buf + Put(tmp) + } + // Restore b.off and len(b.buf). + b.off = 0 + b.buf = b.buf[:m+n] + return m +} diff --git a/vendor/github.com/vmihailenco/bufpool/pool.go b/vendor/github.com/vmihailenco/bufpool/pool.go new file mode 100644 index 000000000..3e1676b48 --- /dev/null +++ b/vendor/github.com/vmihailenco/bufpool/pool.go @@ -0,0 +1,148 @@ +package bufpool + +import ( + "math/bits" + "sync/atomic" +) + +const ( + minBitSize = 6 // 2**6=64 is a CPU cache line size + steps = 20 + + minSize = 1 << minBitSize // 64 bytes + maxSize = 1 << (minBitSize + steps - 1) // 32 mb + maxPoolSize = maxSize << 1 // 64 mb + + defaultServePctile = 0.95 + calibrateCallsThreshold = 42000 + defaultSize = 4096 +) + +// Pool represents byte buffer pool. +// +// Different pools should be used for different usage patterns to achieve better +// performance and lower memory usage. +type Pool struct { + calls [steps]uint32 + calibrating uint32 + + ServePctile float64 // default is 0.95 + serveSize uint32 +} + +func (p *Pool) getServeSize() int { + size := atomic.LoadUint32(&p.serveSize) + if size > 0 { + return int(size) + } + + for i := 0; i < len(p.calls); i++ { + calls := atomic.LoadUint32(&p.calls[i]) + if calls > 10 { + size := indexSize(i) + atomic.CompareAndSwapUint32(&p.serveSize, 0, uint32(size)) + return size + } + } + + return defaultSize +} + +// Get returns an empty buffer from the pool. Returned buffer capacity +// is determined by accumulated usage stats and changes over time. +// +// The buffer may be returned to the pool using Put or retained for further +// usage. In latter case buffer length must be updated using UpdateLen. +func (p *Pool) Get() *Buffer { + buf := Get(p.getServeSize()) + buf.Reset() + return buf +} + +// New returns an empty buffer bypassing the pool. Returned buffer capacity +// is determined by accumulated usage stats and changes over time. +func (p *Pool) New() *Buffer { + return NewBuffer(make([]byte, 0, p.getServeSize())) +} + +// Put returns buffer to the pool. +func (p *Pool) Put(buf *Buffer) { + length := buf.Len() + if length == 0 { + length = buf.Cap() + } + + p.UpdateLen(length) + + // Always put buf to the pool. + Put(buf) +} + +// UpdateLen updates stats about buffer length. +func (p *Pool) UpdateLen(bufLen int) { + idx := index(bufLen) + if atomic.AddUint32(&p.calls[idx], 1) > calibrateCallsThreshold { + p.calibrate() + } +} + +func (p *Pool) calibrate() { + if !atomic.CompareAndSwapUint32(&p.calibrating, 0, 1) { + return + } + + var callSum uint64 + var calls [steps]uint32 + + for i := 0; i < len(p.calls); i++ { + n := atomic.SwapUint32(&p.calls[i], 0) + calls[i] = n + callSum += uint64(n) + } + + serveSum := uint64(float64(callSum) * p.getServePctile()) + var serveSize int + + callSum = 0 + for i, numCall := range &calls { + callSum += uint64(numCall) + + if serveSize == 0 && callSum >= serveSum { + serveSize = indexSize(i) + break + } + } + + atomic.StoreUint32(&p.serveSize, uint32(serveSize)) + atomic.StoreUint32(&p.calibrating, 0) +} + +func (p *Pool) getServePctile() float64 { + if p.ServePctile > 0 { + return p.ServePctile + } + return defaultServePctile +} + +func index(n int) int { + if n == 0 { + return 0 + } + idx := bits.Len32(uint32((n - 1) >> minBitSize)) + if idx >= steps { + idx = steps - 1 + } + return idx +} + +func prevIndex(n int) int { + next := index(n) + if next == 0 || n == indexSize(next) { + return next + } + return next - 1 +} + +func indexSize(idx int) int { + return minSize << uint(idx) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/.golangci.yml b/vendor/github.com/vmihailenco/msgpack/v5/.golangci.yml new file mode 100644 index 000000000..6adfbd655 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/.golangci.yml @@ -0,0 +1,18 @@ +run: + concurrency: 8 + deadline: 5m + tests: false +linters: + enable-all: true + disable: + - gochecknoglobals + - gocognit + - godox + - wsl + - funlen + - gochecknoinits + - gomnd + - nlreturn + - goerr113 + - exhaustive + - nestif diff --git a/vendor/github.com/vmihailenco/msgpack/v5/.prettierrc b/vendor/github.com/vmihailenco/msgpack/v5/.prettierrc new file mode 100644 index 000000000..8b7f044ad --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/.prettierrc @@ -0,0 +1,4 @@ +semi: false +singleQuote: true +proseWrap: always +printWidth: 100 diff --git a/vendor/github.com/vmihailenco/msgpack/v5/.travis.yml b/vendor/github.com/vmihailenco/msgpack/v5/.travis.yml new file mode 100644 index 000000000..e2ce06c49 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/.travis.yml @@ -0,0 +1,20 @@ +sudo: false +language: go + +go: + - 1.15.x + - 1.16.x + - tip + +matrix: + allow_failures: + - go: tip + +env: + - GO111MODULE=on + +go_import_path: github.com/vmihailenco/msgpack + +before_install: + - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go + env GOPATH)/bin v1.31.0 diff --git a/vendor/github.com/vmihailenco/msgpack/v5/CHANGELOG.md b/vendor/github.com/vmihailenco/msgpack/v5/CHANGELOG.md new file mode 100644 index 000000000..a446bb45a --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +See https://msgpack.uptrace.dev/changelog/ diff --git a/vendor/github.com/vmihailenco/msgpack/v5/LICENSE b/vendor/github.com/vmihailenco/msgpack/v5/LICENSE new file mode 100644 index 000000000..b749d0707 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2013 The github.com/vmihailenco/msgpack 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. + +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. diff --git a/vendor/github.com/vmihailenco/msgpack/v5/Makefile b/vendor/github.com/vmihailenco/msgpack/v5/Makefile new file mode 100644 index 000000000..9c3b8dc09 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/Makefile @@ -0,0 +1,7 @@ +all: + go test ./... + go test ./... -short -race + go test ./... -run=NONE -bench=. -benchmem + env GOOS=linux GOARCH=386 go test ./... + go vet + golangci-lint run diff --git a/vendor/github.com/vmihailenco/msgpack/v5/README.md b/vendor/github.com/vmihailenco/msgpack/v5/README.md new file mode 100644 index 000000000..99497fb97 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/README.md @@ -0,0 +1,85 @@ +# MessagePack encoding for Golang + +[![Build Status](https://travis-ci.org/vmihailenco/msgpack.svg)](https://travis-ci.org/vmihailenco/msgpack) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/vmihailenco/msgpack/v5)](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) +[![Documentation](https://img.shields.io/badge/msgpack-documentation-informational)](https://msgpack.uptrace.dev/) +[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) + +> :heart: +> [**Uptrace.dev** - All-in-one tool to optimize performance and monitor errors & logs](https://uptrace.dev/?utm_source=gh-msgpack&utm_campaign=gh-msgpack-var2) + +- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions. +- [Documentation](https://msgpack.uptrace.dev) +- [Reference](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) +- [Examples](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#pkg-examples) + +## Features + +- Primitives, arrays, maps, structs, time.Time and interface{}. +- Appengine \*datastore.Key and datastore.Cursor. +- [CustomEncoder]/[CustomDecoder] interfaces for custom encoding. +- [Extensions](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-RegisterExt) to encode + type information. +- Renaming fields via `msgpack:"my_field_name"` and alias via `msgpack:"alias:another_name"`. +- Omitting individual empty fields via `msgpack:",omitempty"` tag or all + [empty fields in a struct](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal-OmitEmpty). +- [Map keys sorting](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SetSortMapKeys). +- Encoding/decoding all + [structs as arrays](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.UseArrayEncodedStructs) + or + [individual structs](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal-AsArray). +- [Encoder.SetCustomStructTag] with [Decoder.SetCustomStructTag] can turn msgpack into drop-in + replacement for any tag. +- Simple but very fast and efficient + [queries](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Decoder.Query). + +[customencoder]: https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#CustomEncoder +[customdecoder]: https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#CustomDecoder +[encoder.setcustomstructtag]: + https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SetCustomStructTag +[decoder.setcustomstructtag]: + https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Decoder.SetCustomStructTag + +## Installation + +msgpack supports 2 last Go versions and requires support for +[Go modules](https://github.com/golang/go/wiki/Modules). So make sure to initialize a Go module: + +```shell +go mod init github.com/my/repo +``` + +And then install msgpack/v5 (note _v5_ in the import; omitting it is a popular mistake): + +```shell +go get github.com/vmihailenco/msgpack/v5 +``` + +## Quickstart + +```go +import "github.com/vmihailenco/msgpack/v5" + +func ExampleMarshal() { + type Item struct { + Foo string + } + + b, err := msgpack.Marshal(&Item{Foo: "bar"}) + if err != nil { + panic(err) + } + + var item Item + err = msgpack.Unmarshal(b, &item) + if err != nil { + panic(err) + } + fmt.Println(item.Foo) + // Output: bar +} +``` + +## See also + +- [Fast and flexible ORM for sql.DB](https://bun.uptrace.dev) diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode.go b/vendor/github.com/vmihailenco/msgpack/v5/decode.go new file mode 100644 index 000000000..46617c86f --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode.go @@ -0,0 +1,660 @@ +package msgpack + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "reflect" + "sync" + "time" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +const ( + looseInterfaceDecodingFlag uint32 = 1 << iota + disallowUnknownFieldsFlag +) + +const ( + bytesAllocLimit = 1e6 // 1mb + sliceAllocLimit = 1e4 + maxMapSize = 1e6 +) + +type bufReader interface { + io.Reader + io.ByteScanner +} + +//------------------------------------------------------------------------------ + +var decPool = sync.Pool{ + New: func() interface{} { + return NewDecoder(nil) + }, +} + +func GetDecoder() *Decoder { + return decPool.Get().(*Decoder) +} + +func PutDecoder(dec *Decoder) { + dec.r = nil + dec.s = nil + decPool.Put(dec) +} + +//------------------------------------------------------------------------------ + +// Unmarshal decodes the MessagePack-encoded data and stores the result +// in the value pointed to by v. +func Unmarshal(data []byte, v interface{}) error { + dec := GetDecoder() + + dec.Reset(bytes.NewReader(data)) + err := dec.Decode(v) + + PutDecoder(dec) + + return err +} + +// A Decoder reads and decodes MessagePack values from an input stream. +type Decoder struct { + r io.Reader + s io.ByteScanner + buf []byte + + rec []byte // accumulates read data if not nil + + dict []string + flags uint32 + structTag string + mapDecoder func(*Decoder) (interface{}, error) +} + +// NewDecoder returns a new decoder that reads from r. +// +// The decoder introduces its own buffering and may read data from r +// beyond the requested msgpack values. Buffering can be disabled +// by passing a reader that implements io.ByteScanner interface. +func NewDecoder(r io.Reader) *Decoder { + d := new(Decoder) + d.Reset(r) + return d +} + +// Reset discards any buffered data, resets all state, and switches the buffered +// reader to read from r. +func (d *Decoder) Reset(r io.Reader) { + d.ResetDict(r, nil) +} + +// ResetDict is like Reset, but also resets the dict. +func (d *Decoder) ResetDict(r io.Reader, dict []string) { + d.resetReader(r) + d.flags = 0 + d.structTag = "" + d.mapDecoder = nil + d.dict = dict +} + +func (d *Decoder) WithDict(dict []string, fn func(*Decoder) error) error { + oldDict := d.dict + d.dict = dict + err := fn(d) + d.dict = oldDict + return err +} + +func (d *Decoder) resetReader(r io.Reader) { + if br, ok := r.(bufReader); ok { + d.r = br + d.s = br + } else { + br := bufio.NewReader(r) + d.r = br + d.s = br + } +} + +func (d *Decoder) SetMapDecoder(fn func(*Decoder) (interface{}, error)) { + d.mapDecoder = fn +} + +// UseLooseInterfaceDecoding causes decoder to use DecodeInterfaceLoose +// to decode msgpack value into Go interface{}. +func (d *Decoder) UseLooseInterfaceDecoding(on bool) { + if on { + d.flags |= looseInterfaceDecodingFlag + } else { + d.flags &= ^looseInterfaceDecodingFlag + } +} + +// SetCustomStructTag causes the decoder to use the supplied tag as a fallback option +// if there is no msgpack tag. +func (d *Decoder) SetCustomStructTag(tag string) { + d.structTag = tag +} + +// DisallowUnknownFields causes the Decoder to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +func (d *Decoder) DisallowUnknownFields(on bool) { + if on { + d.flags |= disallowUnknownFieldsFlag + } else { + d.flags &= ^disallowUnknownFieldsFlag + } +} + +// UseInternedStrings enables support for decoding interned strings. +func (d *Decoder) UseInternedStrings(on bool) { + if on { + d.flags |= useInternedStringsFlag + } else { + d.flags &= ^useInternedStringsFlag + } +} + +// Buffered returns a reader of the data remaining in the Decoder's buffer. +// The reader is valid until the next call to Decode. +func (d *Decoder) Buffered() io.Reader { + return d.r +} + +//nolint:gocyclo +func (d *Decoder) Decode(v interface{}) error { + var err error + switch v := v.(type) { + case *string: + if v != nil { + *v, err = d.DecodeString() + return err + } + case *[]byte: + if v != nil { + return d.decodeBytesPtr(v) + } + case *int: + if v != nil { + *v, err = d.DecodeInt() + return err + } + case *int8: + if v != nil { + *v, err = d.DecodeInt8() + return err + } + case *int16: + if v != nil { + *v, err = d.DecodeInt16() + return err + } + case *int32: + if v != nil { + *v, err = d.DecodeInt32() + return err + } + case *int64: + if v != nil { + *v, err = d.DecodeInt64() + return err + } + case *uint: + if v != nil { + *v, err = d.DecodeUint() + return err + } + case *uint8: + if v != nil { + *v, err = d.DecodeUint8() + return err + } + case *uint16: + if v != nil { + *v, err = d.DecodeUint16() + return err + } + case *uint32: + if v != nil { + *v, err = d.DecodeUint32() + return err + } + case *uint64: + if v != nil { + *v, err = d.DecodeUint64() + return err + } + case *bool: + if v != nil { + *v, err = d.DecodeBool() + return err + } + case *float32: + if v != nil { + *v, err = d.DecodeFloat32() + return err + } + case *float64: + if v != nil { + *v, err = d.DecodeFloat64() + return err + } + case *[]string: + return d.decodeStringSlicePtr(v) + case *map[string]string: + return d.decodeMapStringStringPtr(v) + case *map[string]interface{}: + return d.decodeMapStringInterfacePtr(v) + case *time.Duration: + if v != nil { + vv, err := d.DecodeInt64() + *v = time.Duration(vv) + return err + } + case *time.Time: + if v != nil { + *v, err = d.DecodeTime() + return err + } + } + + vv := reflect.ValueOf(v) + if !vv.IsValid() { + return errors.New("msgpack: Decode(nil)") + } + if vv.Kind() != reflect.Ptr { + return fmt.Errorf("msgpack: Decode(non-pointer %T)", v) + } + if vv.IsNil() { + return fmt.Errorf("msgpack: Decode(non-settable %T)", v) + } + + vv = vv.Elem() + if vv.Kind() == reflect.Interface { + if !vv.IsNil() { + vv = vv.Elem() + if vv.Kind() != reflect.Ptr { + return fmt.Errorf("msgpack: Decode(non-pointer %s)", vv.Type().String()) + } + } + } + + return d.DecodeValue(vv) +} + +func (d *Decoder) DecodeMulti(v ...interface{}) error { + for _, vv := range v { + if err := d.Decode(vv); err != nil { + return err + } + } + return nil +} + +func (d *Decoder) decodeInterfaceCond() (interface{}, error) { + if d.flags&looseInterfaceDecodingFlag != 0 { + return d.DecodeInterfaceLoose() + } + return d.DecodeInterface() +} + +func (d *Decoder) DecodeValue(v reflect.Value) error { + decode := getDecoder(v.Type()) + return decode(d, v) +} + +func (d *Decoder) DecodeNil() error { + c, err := d.readCode() + if err != nil { + return err + } + if c != msgpcode.Nil { + return fmt.Errorf("msgpack: invalid code=%x decoding nil", c) + } + return nil +} + +func (d *Decoder) decodeNilValue(v reflect.Value) error { + err := d.DecodeNil() + if v.IsNil() { + return err + } + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + v.Set(reflect.Zero(v.Type())) + return err +} + +func (d *Decoder) DecodeBool() (bool, error) { + c, err := d.readCode() + if err != nil { + return false, err + } + return d.bool(c) +} + +func (d *Decoder) bool(c byte) (bool, error) { + if c == msgpcode.False { + return false, nil + } + if c == msgpcode.True { + return true, nil + } + return false, fmt.Errorf("msgpack: invalid code=%x decoding bool", c) +} + +func (d *Decoder) DecodeDuration() (time.Duration, error) { + n, err := d.DecodeInt64() + if err != nil { + return 0, err + } + return time.Duration(n), nil +} + +// DecodeInterface decodes value into interface. It returns following types: +// - nil, +// - bool, +// - int8, int16, int32, int64, +// - uint8, uint16, uint32, uint64, +// - float32 and float64, +// - string, +// - []byte, +// - slices of any of the above, +// - maps of any of the above. +// +// DecodeInterface should be used only when you don't know the type of value +// you are decoding. For example, if you are decoding number it is better to use +// DecodeInt64 for negative numbers and DecodeUint64 for positive numbers. +func (d *Decoder) DecodeInterface() (interface{}, error) { + c, err := d.readCode() + if err != nil { + return nil, err + } + + if msgpcode.IsFixedNum(c) { + return int8(c), nil + } + if msgpcode.IsFixedMap(c) { + err = d.s.UnreadByte() + if err != nil { + return nil, err + } + return d.decodeMapDefault() + } + if msgpcode.IsFixedArray(c) { + return d.decodeSlice(c) + } + if msgpcode.IsFixedString(c) { + return d.string(c) + } + + switch c { + case msgpcode.Nil: + return nil, nil + case msgpcode.False, msgpcode.True: + return d.bool(c) + case msgpcode.Float: + return d.float32(c) + case msgpcode.Double: + return d.float64(c) + case msgpcode.Uint8: + return d.uint8() + case msgpcode.Uint16: + return d.uint16() + case msgpcode.Uint32: + return d.uint32() + case msgpcode.Uint64: + return d.uint64() + case msgpcode.Int8: + return d.int8() + case msgpcode.Int16: + return d.int16() + case msgpcode.Int32: + return d.int32() + case msgpcode.Int64: + return d.int64() + case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32: + return d.bytes(c, nil) + case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32: + return d.string(c) + case msgpcode.Array16, msgpcode.Array32: + return d.decodeSlice(c) + case msgpcode.Map16, msgpcode.Map32: + err = d.s.UnreadByte() + if err != nil { + return nil, err + } + return d.decodeMapDefault() + case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16, + msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32: + return d.decodeInterfaceExt(c) + } + + return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c) +} + +// DecodeInterfaceLoose is like DecodeInterface except that: +// - int8, int16, and int32 are converted to int64, +// - uint8, uint16, and uint32 are converted to uint64, +// - float32 is converted to float64. +// - []byte is converted to string. +func (d *Decoder) DecodeInterfaceLoose() (interface{}, error) { + c, err := d.readCode() + if err != nil { + return nil, err + } + + if msgpcode.IsFixedNum(c) { + return int64(int8(c)), nil + } + if msgpcode.IsFixedMap(c) { + err = d.s.UnreadByte() + if err != nil { + return nil, err + } + return d.decodeMapDefault() + } + if msgpcode.IsFixedArray(c) { + return d.decodeSlice(c) + } + if msgpcode.IsFixedString(c) { + return d.string(c) + } + + switch c { + case msgpcode.Nil: + return nil, nil + case msgpcode.False, msgpcode.True: + return d.bool(c) + case msgpcode.Float, msgpcode.Double: + return d.float64(c) + case msgpcode.Uint8, msgpcode.Uint16, msgpcode.Uint32, msgpcode.Uint64: + return d.uint(c) + case msgpcode.Int8, msgpcode.Int16, msgpcode.Int32, msgpcode.Int64: + return d.int(c) + case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32, + msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32: + return d.string(c) + case msgpcode.Array16, msgpcode.Array32: + return d.decodeSlice(c) + case msgpcode.Map16, msgpcode.Map32: + err = d.s.UnreadByte() + if err != nil { + return nil, err + } + return d.decodeMapDefault() + case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16, + msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32: + return d.decodeInterfaceExt(c) + } + + return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c) +} + +// Skip skips next value. +func (d *Decoder) Skip() error { + c, err := d.readCode() + if err != nil { + return err + } + + if msgpcode.IsFixedNum(c) { + return nil + } + if msgpcode.IsFixedMap(c) { + return d.skipMap(c) + } + if msgpcode.IsFixedArray(c) { + return d.skipSlice(c) + } + if msgpcode.IsFixedString(c) { + return d.skipBytes(c) + } + + switch c { + case msgpcode.Nil, msgpcode.False, msgpcode.True: + return nil + case msgpcode.Uint8, msgpcode.Int8: + return d.skipN(1) + case msgpcode.Uint16, msgpcode.Int16: + return d.skipN(2) + case msgpcode.Uint32, msgpcode.Int32, msgpcode.Float: + return d.skipN(4) + case msgpcode.Uint64, msgpcode.Int64, msgpcode.Double: + return d.skipN(8) + case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32: + return d.skipBytes(c) + case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32: + return d.skipBytes(c) + case msgpcode.Array16, msgpcode.Array32: + return d.skipSlice(c) + case msgpcode.Map16, msgpcode.Map32: + return d.skipMap(c) + case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16, + msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32: + return d.skipExt(c) + } + + return fmt.Errorf("msgpack: unknown code %x", c) +} + +func (d *Decoder) DecodeRaw() (RawMessage, error) { + d.rec = make([]byte, 0) + if err := d.Skip(); err != nil { + return nil, err + } + msg := RawMessage(d.rec) + d.rec = nil + return msg, nil +} + +// PeekCode returns the next MessagePack code without advancing the reader. +// Subpackage msgpack/codes defines the list of available msgpcode. +func (d *Decoder) PeekCode() (byte, error) { + c, err := d.s.ReadByte() + if err != nil { + return 0, err + } + return c, d.s.UnreadByte() +} + +// ReadFull reads exactly len(buf) bytes into the buf. +func (d *Decoder) ReadFull(buf []byte) error { + _, err := readN(d.r, buf, len(buf)) + return err +} + +func (d *Decoder) hasNilCode() bool { + code, err := d.PeekCode() + return err == nil && code == msgpcode.Nil +} + +func (d *Decoder) readCode() (byte, error) { + c, err := d.s.ReadByte() + if err != nil { + return 0, err + } + if d.rec != nil { + d.rec = append(d.rec, c) + } + return c, nil +} + +func (d *Decoder) readFull(b []byte) error { + _, err := io.ReadFull(d.r, b) + if err != nil { + return err + } + if d.rec != nil { + d.rec = append(d.rec, b...) + } + return nil +} + +func (d *Decoder) readN(n int) ([]byte, error) { + var err error + d.buf, err = readN(d.r, d.buf, n) + if err != nil { + return nil, err + } + if d.rec != nil { + // TODO: read directly into d.rec? + d.rec = append(d.rec, d.buf...) + } + return d.buf, nil +} + +func readN(r io.Reader, b []byte, n int) ([]byte, error) { + if b == nil { + if n == 0 { + return make([]byte, 0), nil + } + switch { + case n < 64: + b = make([]byte, 0, 64) + case n <= bytesAllocLimit: + b = make([]byte, 0, n) + default: + b = make([]byte, 0, bytesAllocLimit) + } + } + + if n <= cap(b) { + b = b[:n] + _, err := io.ReadFull(r, b) + return b, err + } + b = b[:cap(b)] + + var pos int + for { + alloc := min(n-len(b), bytesAllocLimit) + b = append(b, make([]byte, alloc)...) + + _, err := io.ReadFull(r, b[pos:]) + if err != nil { + return b, err + } + + if len(b) == n { + break + } + pos = len(b) + } + + return b, nil +} + +func min(a, b int) int { //nolint:unparam + if a <= b { + return a + } + return b +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_map.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_map.go new file mode 100644 index 000000000..52e0526cc --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_map.go @@ -0,0 +1,339 @@ +package msgpack + +import ( + "errors" + "fmt" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +var errArrayStruct = errors.New("msgpack: number of fields in array-encoded struct has changed") + +var ( + mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil)) + mapStringStringType = mapStringStringPtrType.Elem() +) + +var ( + mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil)) + mapStringInterfaceType = mapStringInterfacePtrType.Elem() +) + +func decodeMapValue(d *Decoder, v reflect.Value) error { + n, err := d.DecodeMapLen() + if err != nil { + return err + } + + typ := v.Type() + if n == -1 { + v.Set(reflect.Zero(typ)) + return nil + } + + if v.IsNil() { + v.Set(reflect.MakeMap(typ)) + } + if n == 0 { + return nil + } + + return d.decodeTypedMapValue(v, n) +} + +func (d *Decoder) decodeMapDefault() (interface{}, error) { + if d.mapDecoder != nil { + return d.mapDecoder(d) + } + return d.DecodeMap() +} + +// DecodeMapLen decodes map length. Length is -1 when map is nil. +func (d *Decoder) DecodeMapLen() (int, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + + if msgpcode.IsExt(c) { + if err = d.skipExtHeader(c); err != nil { + return 0, err + } + + c, err = d.readCode() + if err != nil { + return 0, err + } + } + return d.mapLen(c) +} + +func (d *Decoder) mapLen(c byte) (int, error) { + if c == msgpcode.Nil { + return -1, nil + } + if c >= msgpcode.FixedMapLow && c <= msgpcode.FixedMapHigh { + return int(c & msgpcode.FixedMapMask), nil + } + if c == msgpcode.Map16 { + size, err := d.uint16() + return int(size), err + } + if c == msgpcode.Map32 { + size, err := d.uint32() + return int(size), err + } + return 0, unexpectedCodeError{code: c, hint: "map length"} +} + +func decodeMapStringStringValue(d *Decoder, v reflect.Value) error { + mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string) + return d.decodeMapStringStringPtr(mptr) +} + +func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error { + size, err := d.DecodeMapLen() + if err != nil { + return err + } + if size == -1 { + *ptr = nil + return nil + } + + m := *ptr + if m == nil { + *ptr = make(map[string]string, min(size, maxMapSize)) + m = *ptr + } + + for i := 0; i < size; i++ { + mk, err := d.DecodeString() + if err != nil { + return err + } + mv, err := d.DecodeString() + if err != nil { + return err + } + m[mk] = mv + } + + return nil +} + +func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error { + ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{}) + return d.decodeMapStringInterfacePtr(ptr) +} + +func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error { + m, err := d.DecodeMap() + if err != nil { + return err + } + *ptr = m + return nil +} + +func (d *Decoder) DecodeMap() (map[string]interface{}, error) { + n, err := d.DecodeMapLen() + if err != nil { + return nil, err + } + + if n == -1 { + return nil, nil + } + + m := make(map[string]interface{}, min(n, maxMapSize)) + + for i := 0; i < n; i++ { + mk, err := d.DecodeString() + if err != nil { + return nil, err + } + mv, err := d.decodeInterfaceCond() + if err != nil { + return nil, err + } + m[mk] = mv + } + + return m, nil +} + +func (d *Decoder) DecodeUntypedMap() (map[interface{}]interface{}, error) { + n, err := d.DecodeMapLen() + if err != nil { + return nil, err + } + + if n == -1 { + return nil, nil + } + + m := make(map[interface{}]interface{}, min(n, maxMapSize)) + + for i := 0; i < n; i++ { + mk, err := d.decodeInterfaceCond() + if err != nil { + return nil, err + } + + mv, err := d.decodeInterfaceCond() + if err != nil { + return nil, err + } + + m[mk] = mv + } + + return m, nil +} + +// DecodeTypedMap decodes a typed map. Typed map is a map that has a fixed type for keys and values. +// Key and value types may be different. +func (d *Decoder) DecodeTypedMap() (interface{}, error) { + n, err := d.DecodeMapLen() + if err != nil { + return nil, err + } + if n <= 0 { + return nil, nil + } + + key, err := d.decodeInterfaceCond() + if err != nil { + return nil, err + } + + value, err := d.decodeInterfaceCond() + if err != nil { + return nil, err + } + + keyType := reflect.TypeOf(key) + valueType := reflect.TypeOf(value) + + if !keyType.Comparable() { + return nil, fmt.Errorf("msgpack: unsupported map key: %s", keyType.String()) + } + + mapType := reflect.MapOf(keyType, valueType) + mapValue := reflect.MakeMap(mapType) + mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value)) + + n-- + if err := d.decodeTypedMapValue(mapValue, n); err != nil { + return nil, err + } + + return mapValue.Interface(), nil +} + +func (d *Decoder) decodeTypedMapValue(v reflect.Value, n int) error { + typ := v.Type() + keyType := typ.Key() + valueType := typ.Elem() + + for i := 0; i < n; i++ { + mk := reflect.New(keyType).Elem() + if err := d.DecodeValue(mk); err != nil { + return err + } + + mv := reflect.New(valueType).Elem() + if err := d.DecodeValue(mv); err != nil { + return err + } + + v.SetMapIndex(mk, mv) + } + + return nil +} + +func (d *Decoder) skipMap(c byte) error { + n, err := d.mapLen(c) + if err != nil { + return err + } + for i := 0; i < n; i++ { + if err := d.Skip(); err != nil { + return err + } + if err := d.Skip(); err != nil { + return err + } + } + return nil +} + +func decodeStructValue(d *Decoder, v reflect.Value) error { + c, err := d.readCode() + if err != nil { + return err + } + + n, err := d.mapLen(c) + if err == nil { + return d.decodeStruct(v, n) + } + + var err2 error + n, err2 = d.arrayLen(c) + if err2 != nil { + return err + } + + if n <= 0 { + v.Set(reflect.Zero(v.Type())) + return nil + } + + fields := structs.Fields(v.Type(), d.structTag) + if n != len(fields.List) { + return errArrayStruct + } + + for _, f := range fields.List { + if err := f.DecodeValue(d, v); err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) decodeStruct(v reflect.Value, n int) error { + if n == -1 { + v.Set(reflect.Zero(v.Type())) + return nil + } + + fields := structs.Fields(v.Type(), d.structTag) + for i := 0; i < n; i++ { + name, err := d.decodeStringTemp() + if err != nil { + return err + } + + if f := fields.Map[name]; f != nil { + if err := f.DecodeValue(d, v); err != nil { + return err + } + continue + } + + if d.flags&disallowUnknownFieldsFlag != 0 { + return fmt.Errorf("msgpack: unknown field %q", name) + } + if err := d.Skip(); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_number.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_number.go new file mode 100644 index 000000000..45d6a7418 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_number.go @@ -0,0 +1,295 @@ +package msgpack + +import ( + "fmt" + "math" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +func (d *Decoder) skipN(n int) error { + _, err := d.readN(n) + return err +} + +func (d *Decoder) uint8() (uint8, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return c, nil +} + +func (d *Decoder) int8() (int8, error) { + n, err := d.uint8() + return int8(n), err +} + +func (d *Decoder) uint16() (uint16, error) { + b, err := d.readN(2) + if err != nil { + return 0, err + } + return (uint16(b[0]) << 8) | uint16(b[1]), nil +} + +func (d *Decoder) int16() (int16, error) { + n, err := d.uint16() + return int16(n), err +} + +func (d *Decoder) uint32() (uint32, error) { + b, err := d.readN(4) + if err != nil { + return 0, err + } + n := (uint32(b[0]) << 24) | + (uint32(b[1]) << 16) | + (uint32(b[2]) << 8) | + uint32(b[3]) + return n, nil +} + +func (d *Decoder) int32() (int32, error) { + n, err := d.uint32() + return int32(n), err +} + +func (d *Decoder) uint64() (uint64, error) { + b, err := d.readN(8) + if err != nil { + return 0, err + } + n := (uint64(b[0]) << 56) | + (uint64(b[1]) << 48) | + (uint64(b[2]) << 40) | + (uint64(b[3]) << 32) | + (uint64(b[4]) << 24) | + (uint64(b[5]) << 16) | + (uint64(b[6]) << 8) | + uint64(b[7]) + return n, nil +} + +func (d *Decoder) int64() (int64, error) { + n, err := d.uint64() + return int64(n), err +} + +// DecodeUint64 decodes msgpack int8/16/32/64 and uint8/16/32/64 +// into Go uint64. +func (d *Decoder) DecodeUint64() (uint64, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return d.uint(c) +} + +func (d *Decoder) uint(c byte) (uint64, error) { + if c == msgpcode.Nil { + return 0, nil + } + if msgpcode.IsFixedNum(c) { + return uint64(int8(c)), nil + } + switch c { + case msgpcode.Uint8: + n, err := d.uint8() + return uint64(n), err + case msgpcode.Int8: + n, err := d.int8() + return uint64(n), err + case msgpcode.Uint16: + n, err := d.uint16() + return uint64(n), err + case msgpcode.Int16: + n, err := d.int16() + return uint64(n), err + case msgpcode.Uint32: + n, err := d.uint32() + return uint64(n), err + case msgpcode.Int32: + n, err := d.int32() + return uint64(n), err + case msgpcode.Uint64, msgpcode.Int64: + return d.uint64() + } + return 0, fmt.Errorf("msgpack: invalid code=%x decoding uint64", c) +} + +// DecodeInt64 decodes msgpack int8/16/32/64 and uint8/16/32/64 +// into Go int64. +func (d *Decoder) DecodeInt64() (int64, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return d.int(c) +} + +func (d *Decoder) int(c byte) (int64, error) { + if c == msgpcode.Nil { + return 0, nil + } + if msgpcode.IsFixedNum(c) { + return int64(int8(c)), nil + } + switch c { + case msgpcode.Uint8: + n, err := d.uint8() + return int64(n), err + case msgpcode.Int8: + n, err := d.uint8() + return int64(int8(n)), err + case msgpcode.Uint16: + n, err := d.uint16() + return int64(n), err + case msgpcode.Int16: + n, err := d.uint16() + return int64(int16(n)), err + case msgpcode.Uint32: + n, err := d.uint32() + return int64(n), err + case msgpcode.Int32: + n, err := d.uint32() + return int64(int32(n)), err + case msgpcode.Uint64, msgpcode.Int64: + n, err := d.uint64() + return int64(n), err + } + return 0, fmt.Errorf("msgpack: invalid code=%x decoding int64", c) +} + +func (d *Decoder) DecodeFloat32() (float32, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return d.float32(c) +} + +func (d *Decoder) float32(c byte) (float32, error) { + if c == msgpcode.Float { + n, err := d.uint32() + if err != nil { + return 0, err + } + return math.Float32frombits(n), nil + } + + n, err := d.int(c) + if err != nil { + return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c) + } + return float32(n), nil +} + +// DecodeFloat64 decodes msgpack float32/64 into Go float64. +func (d *Decoder) DecodeFloat64() (float64, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return d.float64(c) +} + +func (d *Decoder) float64(c byte) (float64, error) { + switch c { + case msgpcode.Float: + n, err := d.float32(c) + if err != nil { + return 0, err + } + return float64(n), nil + case msgpcode.Double: + n, err := d.uint64() + if err != nil { + return 0, err + } + return math.Float64frombits(n), nil + } + + n, err := d.int(c) + if err != nil { + return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c) + } + return float64(n), nil +} + +func (d *Decoder) DecodeUint() (uint, error) { + n, err := d.DecodeUint64() + return uint(n), err +} + +func (d *Decoder) DecodeUint8() (uint8, error) { + n, err := d.DecodeUint64() + return uint8(n), err +} + +func (d *Decoder) DecodeUint16() (uint16, error) { + n, err := d.DecodeUint64() + return uint16(n), err +} + +func (d *Decoder) DecodeUint32() (uint32, error) { + n, err := d.DecodeUint64() + return uint32(n), err +} + +func (d *Decoder) DecodeInt() (int, error) { + n, err := d.DecodeInt64() + return int(n), err +} + +func (d *Decoder) DecodeInt8() (int8, error) { + n, err := d.DecodeInt64() + return int8(n), err +} + +func (d *Decoder) DecodeInt16() (int16, error) { + n, err := d.DecodeInt64() + return int16(n), err +} + +func (d *Decoder) DecodeInt32() (int32, error) { + n, err := d.DecodeInt64() + return int32(n), err +} + +func decodeFloat32Value(d *Decoder, v reflect.Value) error { + f, err := d.DecodeFloat32() + if err != nil { + return err + } + v.SetFloat(float64(f)) + return nil +} + +func decodeFloat64Value(d *Decoder, v reflect.Value) error { + f, err := d.DecodeFloat64() + if err != nil { + return err + } + v.SetFloat(f) + return nil +} + +func decodeInt64Value(d *Decoder, v reflect.Value) error { + n, err := d.DecodeInt64() + if err != nil { + return err + } + v.SetInt(n) + return nil +} + +func decodeUint64Value(d *Decoder, v reflect.Value) error { + n, err := d.DecodeUint64() + if err != nil { + return err + } + v.SetUint(n) + return nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go new file mode 100644 index 000000000..c302ed1f3 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go @@ -0,0 +1,158 @@ +package msgpack + +import ( + "fmt" + "strconv" + "strings" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type queryResult struct { + query string + key string + hasAsterisk bool + + values []interface{} +} + +func (q *queryResult) nextKey() { + ind := strings.IndexByte(q.query, '.') + if ind == -1 { + q.key = q.query + q.query = "" + return + } + q.key = q.query[:ind] + q.query = q.query[ind+1:] +} + +// Query extracts data specified by the query from the msgpack stream skipping +// any other data. Query consists of map keys and array indexes separated with dot, +// e.g. key1.0.key2. +func (d *Decoder) Query(query string) ([]interface{}, error) { + res := queryResult{ + query: query, + } + if err := d.query(&res); err != nil { + return nil, err + } + return res.values, nil +} + +func (d *Decoder) query(q *queryResult) error { + q.nextKey() + if q.key == "" { + v, err := d.decodeInterfaceCond() + if err != nil { + return err + } + q.values = append(q.values, v) + return nil + } + + code, err := d.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code): + err = d.queryMapKey(q) + case code == msgpcode.Array16 || code == msgpcode.Array32 || msgpcode.IsFixedArray(code): + err = d.queryArrayIndex(q) + default: + err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key) + } + return err +} + +func (d *Decoder) queryMapKey(q *queryResult) error { + n, err := d.DecodeMapLen() + if err != nil { + return err + } + if n == -1 { + return nil + } + + for i := 0; i < n; i++ { + key, err := d.decodeStringTemp() + if err != nil { + return err + } + + if key == q.key { + if err := d.query(q); err != nil { + return err + } + if q.hasAsterisk { + return d.skipNext((n - i - 1) * 2) + } + return nil + } + + if err := d.Skip(); err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) queryArrayIndex(q *queryResult) error { + n, err := d.DecodeArrayLen() + if err != nil { + return err + } + if n == -1 { + return nil + } + + if q.key == "*" { + q.hasAsterisk = true + + query := q.query + for i := 0; i < n; i++ { + q.query = query + if err := d.query(q); err != nil { + return err + } + } + + q.hasAsterisk = false + return nil + } + + ind, err := strconv.Atoi(q.key) + if err != nil { + return err + } + + for i := 0; i < n; i++ { + if i == ind { + if err := d.query(q); err != nil { + return err + } + if q.hasAsterisk { + return d.skipNext(n - i - 1) + } + return nil + } + + if err := d.Skip(); err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) skipNext(n int) error { + for i := 0; i < n; i++ { + if err := d.Skip(); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_slice.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_slice.go new file mode 100644 index 000000000..db6f7c547 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_slice.go @@ -0,0 +1,191 @@ +package msgpack + +import ( + "fmt" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +var sliceStringPtrType = reflect.TypeOf((*[]string)(nil)) + +// DecodeArrayLen decodes array length. Length is -1 when array is nil. +func (d *Decoder) DecodeArrayLen() (int, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return d.arrayLen(c) +} + +func (d *Decoder) arrayLen(c byte) (int, error) { + if c == msgpcode.Nil { + return -1, nil + } else if c >= msgpcode.FixedArrayLow && c <= msgpcode.FixedArrayHigh { + return int(c & msgpcode.FixedArrayMask), nil + } + switch c { + case msgpcode.Array16: + n, err := d.uint16() + return int(n), err + case msgpcode.Array32: + n, err := d.uint32() + return int(n), err + } + return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c) +} + +func decodeStringSliceValue(d *Decoder, v reflect.Value) error { + ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string) + return d.decodeStringSlicePtr(ptr) +} + +func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error { + n, err := d.DecodeArrayLen() + if err != nil { + return err + } + if n == -1 { + return nil + } + + ss := makeStrings(*ptr, n) + for i := 0; i < n; i++ { + s, err := d.DecodeString() + if err != nil { + return err + } + ss = append(ss, s) + } + *ptr = ss + + return nil +} + +func makeStrings(s []string, n int) []string { + if n > sliceAllocLimit { + n = sliceAllocLimit + } + + if s == nil { + return make([]string, 0, n) + } + + if cap(s) >= n { + return s[:0] + } + + s = s[:cap(s)] + s = append(s, make([]string, n-len(s))...) + return s[:0] +} + +func decodeSliceValue(d *Decoder, v reflect.Value) error { + n, err := d.DecodeArrayLen() + if err != nil { + return err + } + + if n == -1 { + v.Set(reflect.Zero(v.Type())) + return nil + } + if n == 0 && v.IsNil() { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + return nil + } + + if v.Cap() >= n { + v.Set(v.Slice(0, n)) + } else if v.Len() < v.Cap() { + v.Set(v.Slice(0, v.Cap())) + } + + for i := 0; i < n; i++ { + if i >= v.Len() { + v.Set(growSliceValue(v, n)) + } + elem := v.Index(i) + if err := d.DecodeValue(elem); err != nil { + return err + } + } + + return nil +} + +func growSliceValue(v reflect.Value, n int) reflect.Value { + diff := n - v.Len() + if diff > sliceAllocLimit { + diff = sliceAllocLimit + } + v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff)) + return v +} + +func decodeArrayValue(d *Decoder, v reflect.Value) error { + n, err := d.DecodeArrayLen() + if err != nil { + return err + } + + if n == -1 { + return nil + } + if n > v.Len() { + return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n) + } + + for i := 0; i < n; i++ { + sv := v.Index(i) + if err := d.DecodeValue(sv); err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) DecodeSlice() ([]interface{}, error) { + c, err := d.readCode() + if err != nil { + return nil, err + } + return d.decodeSlice(c) +} + +func (d *Decoder) decodeSlice(c byte) ([]interface{}, error) { + n, err := d.arrayLen(c) + if err != nil { + return nil, err + } + if n == -1 { + return nil, nil + } + + s := make([]interface{}, 0, min(n, sliceAllocLimit)) + for i := 0; i < n; i++ { + v, err := d.decodeInterfaceCond() + if err != nil { + return nil, err + } + s = append(s, v) + } + + return s, nil +} + +func (d *Decoder) skipSlice(c byte) error { + n, err := d.arrayLen(c) + if err != nil { + return err + } + + for i := 0; i < n; i++ { + if err := d.Skip(); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_string.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_string.go new file mode 100644 index 000000000..e837e08bf --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_string.go @@ -0,0 +1,192 @@ +package msgpack + +import ( + "fmt" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +func (d *Decoder) bytesLen(c byte) (int, error) { + if c == msgpcode.Nil { + return -1, nil + } + + if msgpcode.IsFixedString(c) { + return int(c & msgpcode.FixedStrMask), nil + } + + switch c { + case msgpcode.Str8, msgpcode.Bin8: + n, err := d.uint8() + return int(n), err + case msgpcode.Str16, msgpcode.Bin16: + n, err := d.uint16() + return int(n), err + case msgpcode.Str32, msgpcode.Bin32: + n, err := d.uint32() + return int(n), err + } + + return 0, fmt.Errorf("msgpack: invalid code=%x decoding string/bytes length", c) +} + +func (d *Decoder) DecodeString() (string, error) { + if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 { + return d.decodeInternedString(intern) + } + + c, err := d.readCode() + if err != nil { + return "", err + } + return d.string(c) +} + +func (d *Decoder) string(c byte) (string, error) { + n, err := d.bytesLen(c) + if err != nil { + return "", err + } + return d.stringWithLen(n) +} + +func (d *Decoder) stringWithLen(n int) (string, error) { + if n <= 0 { + return "", nil + } + b, err := d.readN(n) + return string(b), err +} + +func decodeStringValue(d *Decoder, v reflect.Value) error { + s, err := d.DecodeString() + if err != nil { + return err + } + v.SetString(s) + return nil +} + +func (d *Decoder) DecodeBytesLen() (int, error) { + c, err := d.readCode() + if err != nil { + return 0, err + } + return d.bytesLen(c) +} + +func (d *Decoder) DecodeBytes() ([]byte, error) { + c, err := d.readCode() + if err != nil { + return nil, err + } + return d.bytes(c, nil) +} + +func (d *Decoder) bytes(c byte, b []byte) ([]byte, error) { + n, err := d.bytesLen(c) + if err != nil { + return nil, err + } + if n == -1 { + return nil, nil + } + return readN(d.r, b, n) +} + +func (d *Decoder) decodeStringTemp() (string, error) { + if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 { + return d.decodeInternedString(intern) + } + + c, err := d.readCode() + if err != nil { + return "", err + } + + n, err := d.bytesLen(c) + if err != nil { + return "", err + } + if n == -1 { + return "", nil + } + + b, err := d.readN(n) + if err != nil { + return "", err + } + + return bytesToString(b), nil +} + +func (d *Decoder) decodeBytesPtr(ptr *[]byte) error { + c, err := d.readCode() + if err != nil { + return err + } + return d.bytesPtr(c, ptr) +} + +func (d *Decoder) bytesPtr(c byte, ptr *[]byte) error { + n, err := d.bytesLen(c) + if err != nil { + return err + } + if n == -1 { + *ptr = nil + return nil + } + + *ptr, err = readN(d.r, *ptr, n) + return err +} + +func (d *Decoder) skipBytes(c byte) error { + n, err := d.bytesLen(c) + if err != nil { + return err + } + if n <= 0 { + return nil + } + return d.skipN(n) +} + +func decodeBytesValue(d *Decoder, v reflect.Value) error { + c, err := d.readCode() + if err != nil { + return err + } + + b, err := d.bytes(c, v.Bytes()) + if err != nil { + return err + } + + v.SetBytes(b) + + return nil +} + +func decodeByteArrayValue(d *Decoder, v reflect.Value) error { + c, err := d.readCode() + if err != nil { + return err + } + + n, err := d.bytesLen(c) + if err != nil { + return err + } + if n == -1 { + return nil + } + if n > v.Len() { + return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n) + } + + b := v.Slice(0, n).Bytes() + return d.readFull(b) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_value.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_value.go new file mode 100644 index 000000000..d2ff2aea5 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_value.go @@ -0,0 +1,250 @@ +package msgpack + +import ( + "encoding" + "errors" + "fmt" + "reflect" +) + +var ( + interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() + stringType = reflect.TypeOf((*string)(nil)).Elem() +) + +var valueDecoders []decoderFunc + +//nolint:gochecknoinits +func init() { + valueDecoders = []decoderFunc{ + reflect.Bool: decodeBoolValue, + reflect.Int: decodeInt64Value, + reflect.Int8: decodeInt64Value, + reflect.Int16: decodeInt64Value, + reflect.Int32: decodeInt64Value, + reflect.Int64: decodeInt64Value, + reflect.Uint: decodeUint64Value, + reflect.Uint8: decodeUint64Value, + reflect.Uint16: decodeUint64Value, + reflect.Uint32: decodeUint64Value, + reflect.Uint64: decodeUint64Value, + reflect.Float32: decodeFloat32Value, + reflect.Float64: decodeFloat64Value, + reflect.Complex64: decodeUnsupportedValue, + reflect.Complex128: decodeUnsupportedValue, + reflect.Array: decodeArrayValue, + reflect.Chan: decodeUnsupportedValue, + reflect.Func: decodeUnsupportedValue, + reflect.Interface: decodeInterfaceValue, + reflect.Map: decodeMapValue, + reflect.Ptr: decodeUnsupportedValue, + reflect.Slice: decodeSliceValue, + reflect.String: decodeStringValue, + reflect.Struct: decodeStructValue, + reflect.UnsafePointer: decodeUnsupportedValue, + } +} + +func getDecoder(typ reflect.Type) decoderFunc { + if v, ok := typeDecMap.Load(typ); ok { + return v.(decoderFunc) + } + fn := _getDecoder(typ) + typeDecMap.Store(typ, fn) + return fn +} + +func _getDecoder(typ reflect.Type) decoderFunc { + kind := typ.Kind() + + if kind == reflect.Ptr { + if _, ok := typeDecMap.Load(typ.Elem()); ok { + return ptrValueDecoder(typ) + } + } + + if typ.Implements(customDecoderType) { + return nilAwareDecoder(typ, decodeCustomValue) + } + if typ.Implements(unmarshalerType) { + return nilAwareDecoder(typ, unmarshalValue) + } + if typ.Implements(binaryUnmarshalerType) { + return nilAwareDecoder(typ, unmarshalBinaryValue) + } + if typ.Implements(textUnmarshalerType) { + return nilAwareDecoder(typ, unmarshalTextValue) + } + + // Addressable struct field value. + if kind != reflect.Ptr { + ptr := reflect.PtrTo(typ) + if ptr.Implements(customDecoderType) { + return addrDecoder(nilAwareDecoder(typ, decodeCustomValue)) + } + if ptr.Implements(unmarshalerType) { + return addrDecoder(nilAwareDecoder(typ, unmarshalValue)) + } + if ptr.Implements(binaryUnmarshalerType) { + return addrDecoder(nilAwareDecoder(typ, unmarshalBinaryValue)) + } + if ptr.Implements(textUnmarshalerType) { + return addrDecoder(nilAwareDecoder(typ, unmarshalTextValue)) + } + } + + switch kind { + case reflect.Ptr: + return ptrValueDecoder(typ) + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + return decodeBytesValue + } + if elem == stringType { + return decodeStringSliceValue + } + case reflect.Array: + if typ.Elem().Kind() == reflect.Uint8 { + return decodeByteArrayValue + } + case reflect.Map: + if typ.Key() == stringType { + switch typ.Elem() { + case stringType: + return decodeMapStringStringValue + case interfaceType: + return decodeMapStringInterfaceValue + } + } + } + + return valueDecoders[kind] +} + +func ptrValueDecoder(typ reflect.Type) decoderFunc { + decoder := getDecoder(typ.Elem()) + return func(d *Decoder, v reflect.Value) error { + if d.hasNilCode() { + if !v.IsNil() { + v.Set(reflect.Zero(v.Type())) + } + return d.DecodeNil() + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + return decoder(d, v.Elem()) + } +} + +func addrDecoder(fn decoderFunc) decoderFunc { + return func(d *Decoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface()) + } + return fn(d, v.Addr()) + } +} + +func nilAwareDecoder(typ reflect.Type, fn decoderFunc) decoderFunc { + if nilable(typ.Kind()) { + return func(d *Decoder, v reflect.Value) error { + if d.hasNilCode() { + return d.decodeNilValue(v) + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + return fn(d, v) + } + } + + return func(d *Decoder, v reflect.Value) error { + if d.hasNilCode() { + return d.decodeNilValue(v) + } + return fn(d, v) + } +} + +func decodeBoolValue(d *Decoder, v reflect.Value) error { + flag, err := d.DecodeBool() + if err != nil { + return err + } + v.SetBool(flag) + return nil +} + +func decodeInterfaceValue(d *Decoder, v reflect.Value) error { + if v.IsNil() { + return d.interfaceValue(v) + } + return d.DecodeValue(v.Elem()) +} + +func (d *Decoder) interfaceValue(v reflect.Value) error { + vv, err := d.decodeInterfaceCond() + if err != nil { + return err + } + + if vv != nil { + if v.Type() == errorType { + if vv, ok := vv.(string); ok { + v.Set(reflect.ValueOf(errors.New(vv))) + return nil + } + } + + v.Set(reflect.ValueOf(vv)) + } + + return nil +} + +func decodeUnsupportedValue(d *Decoder, v reflect.Value) error { + return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type()) +} + +//------------------------------------------------------------------------------ + +func decodeCustomValue(d *Decoder, v reflect.Value) error { + decoder := v.Interface().(CustomDecoder) + return decoder.DecodeMsgpack(d) +} + +func unmarshalValue(d *Decoder, v reflect.Value) error { + var b []byte + + d.rec = make([]byte, 0, 64) + if err := d.Skip(); err != nil { + return err + } + b = d.rec + d.rec = nil + + unmarshaler := v.Interface().(Unmarshaler) + return unmarshaler.UnmarshalMsgpack(b) +} + +func unmarshalBinaryValue(d *Decoder, v reflect.Value) error { + data, err := d.DecodeBytes() + if err != nil { + return err + } + + unmarshaler := v.Interface().(encoding.BinaryUnmarshaler) + return unmarshaler.UnmarshalBinary(data) +} + +func unmarshalTextValue(d *Decoder, v reflect.Value) error { + data, err := d.DecodeBytes() + if err != nil { + return err + } + + unmarshaler := v.Interface().(encoding.TextUnmarshaler) + return unmarshaler.UnmarshalText(data) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/encode.go b/vendor/github.com/vmihailenco/msgpack/v5/encode.go new file mode 100644 index 000000000..0ef6212e6 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/encode.go @@ -0,0 +1,269 @@ +package msgpack + +import ( + "bytes" + "io" + "reflect" + "sync" + "time" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +const ( + sortMapKeysFlag uint32 = 1 << iota + arrayEncodedStructsFlag + useCompactIntsFlag + useCompactFloatsFlag + useInternedStringsFlag + omitEmptyFlag +) + +type writer interface { + io.Writer + WriteByte(byte) error +} + +type byteWriter struct { + io.Writer +} + +func newByteWriter(w io.Writer) byteWriter { + return byteWriter{ + Writer: w, + } +} + +func (bw byteWriter) WriteByte(c byte) error { + _, err := bw.Write([]byte{c}) + return err +} + +//------------------------------------------------------------------------------ + +var encPool = sync.Pool{ + New: func() interface{} { + return NewEncoder(nil) + }, +} + +func GetEncoder() *Encoder { + return encPool.Get().(*Encoder) +} + +func PutEncoder(enc *Encoder) { + enc.w = nil + encPool.Put(enc) +} + +// Marshal returns the MessagePack encoding of v. +func Marshal(v interface{}) ([]byte, error) { + enc := GetEncoder() + + var buf bytes.Buffer + enc.Reset(&buf) + + err := enc.Encode(v) + b := buf.Bytes() + + PutEncoder(enc) + + if err != nil { + return nil, err + } + return b, err +} + +type Encoder struct { + w writer + + buf []byte + timeBuf []byte + + dict map[string]int + + flags uint32 + structTag string +} + +// NewEncoder returns a new encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + e := &Encoder{ + buf: make([]byte, 9), + } + e.Reset(w) + return e +} + +// Writer returns the Encoder's writer. +func (e *Encoder) Writer() io.Writer { + return e.w +} + +// Reset discards any buffered data, resets all state, and switches the writer to write to w. +func (e *Encoder) Reset(w io.Writer) { + e.ResetDict(w, nil) +} + +// ResetDict is like Reset, but also resets the dict. +func (e *Encoder) ResetDict(w io.Writer, dict map[string]int) { + e.resetWriter(w) + e.flags = 0 + e.structTag = "" + e.dict = dict +} + +func (e *Encoder) WithDict(dict map[string]int, fn func(*Encoder) error) error { + oldDict := e.dict + e.dict = dict + err := fn(e) + e.dict = oldDict + return err +} + +func (e *Encoder) resetWriter(w io.Writer) { + if bw, ok := w.(writer); ok { + e.w = bw + } else { + e.w = newByteWriter(w) + } +} + +// SetSortMapKeys causes the Encoder to encode map keys in increasing order. +// Supported map types are: +// - map[string]string +// - map[string]interface{} +func (e *Encoder) SetSortMapKeys(on bool) *Encoder { + if on { + e.flags |= sortMapKeysFlag + } else { + e.flags &= ^sortMapKeysFlag + } + return e +} + +// SetCustomStructTag causes the Encoder to use a custom struct tag as +// fallback option if there is no msgpack tag. +func (e *Encoder) SetCustomStructTag(tag string) { + e.structTag = tag +} + +// SetOmitEmpty causes the Encoder to omit empty values by default. +func (e *Encoder) SetOmitEmpty(on bool) { + if on { + e.flags |= omitEmptyFlag + } else { + e.flags &= ^omitEmptyFlag + } +} + +// UseArrayEncodedStructs causes the Encoder to encode Go structs as msgpack arrays. +func (e *Encoder) UseArrayEncodedStructs(on bool) { + if on { + e.flags |= arrayEncodedStructsFlag + } else { + e.flags &= ^arrayEncodedStructsFlag + } +} + +// UseCompactEncoding causes the Encoder to chose the most compact encoding. +// For example, it allows to encode small Go int64 as msgpack int8 saving 7 bytes. +func (e *Encoder) UseCompactInts(on bool) { + if on { + e.flags |= useCompactIntsFlag + } else { + e.flags &= ^useCompactIntsFlag + } +} + +// UseCompactFloats causes the Encoder to chose a compact integer encoding +// for floats that can be represented as integers. +func (e *Encoder) UseCompactFloats(on bool) { + if on { + e.flags |= useCompactFloatsFlag + } else { + e.flags &= ^useCompactFloatsFlag + } +} + +// UseInternedStrings causes the Encoder to intern strings. +func (e *Encoder) UseInternedStrings(on bool) { + if on { + e.flags |= useInternedStringsFlag + } else { + e.flags &= ^useInternedStringsFlag + } +} + +func (e *Encoder) Encode(v interface{}) error { + switch v := v.(type) { + case nil: + return e.EncodeNil() + case string: + return e.EncodeString(v) + case []byte: + return e.EncodeBytes(v) + case int: + return e.EncodeInt(int64(v)) + case int64: + return e.encodeInt64Cond(v) + case uint: + return e.EncodeUint(uint64(v)) + case uint64: + return e.encodeUint64Cond(v) + case bool: + return e.EncodeBool(v) + case float32: + return e.EncodeFloat32(v) + case float64: + return e.EncodeFloat64(v) + case time.Duration: + return e.encodeInt64Cond(int64(v)) + case time.Time: + return e.EncodeTime(v) + } + return e.EncodeValue(reflect.ValueOf(v)) +} + +func (e *Encoder) EncodeMulti(v ...interface{}) error { + for _, vv := range v { + if err := e.Encode(vv); err != nil { + return err + } + } + return nil +} + +func (e *Encoder) EncodeValue(v reflect.Value) error { + fn := getEncoder(v.Type()) + return fn(e, v) +} + +func (e *Encoder) EncodeNil() error { + return e.writeCode(msgpcode.Nil) +} + +func (e *Encoder) EncodeBool(value bool) error { + if value { + return e.writeCode(msgpcode.True) + } + return e.writeCode(msgpcode.False) +} + +func (e *Encoder) EncodeDuration(d time.Duration) error { + return e.EncodeInt(int64(d)) +} + +func (e *Encoder) writeCode(c byte) error { + return e.w.WriteByte(c) +} + +func (e *Encoder) write(b []byte) error { + _, err := e.w.Write(b) + return err +} + +func (e *Encoder) writeString(s string) error { + _, err := e.w.Write(stringToBytes(s)) + return err +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/encode_map.go b/vendor/github.com/vmihailenco/msgpack/v5/encode_map.go new file mode 100644 index 000000000..02cb6c132 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/encode_map.go @@ -0,0 +1,178 @@ +package msgpack + +import ( + "math" + "reflect" + "sort" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +func encodeMapValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + + if err := e.EncodeMapLen(v.Len()); err != nil { + return err + } + + for _, key := range v.MapKeys() { + if err := e.EncodeValue(key); err != nil { + return err + } + if err := e.EncodeValue(v.MapIndex(key)); err != nil { + return err + } + } + + return nil +} + +func encodeMapStringStringValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + + if err := e.EncodeMapLen(v.Len()); err != nil { + return err + } + + m := v.Convert(mapStringStringType).Interface().(map[string]string) + if e.flags&sortMapKeysFlag != 0 { + return e.encodeSortedMapStringString(m) + } + + for mk, mv := range m { + if err := e.EncodeString(mk); err != nil { + return err + } + if err := e.EncodeString(mv); err != nil { + return err + } + } + + return nil +} + +func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{}) + if e.flags&sortMapKeysFlag != 0 { + return e.EncodeMapSorted(m) + } + return e.EncodeMap(m) +} + +func (e *Encoder) EncodeMap(m map[string]interface{}) error { + if m == nil { + return e.EncodeNil() + } + if err := e.EncodeMapLen(len(m)); err != nil { + return err + } + for mk, mv := range m { + if err := e.EncodeString(mk); err != nil { + return err + } + if err := e.Encode(mv); err != nil { + return err + } + } + return nil +} + +func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error { + if m == nil { + return e.EncodeNil() + } + if err := e.EncodeMapLen(len(m)); err != nil { + return err + } + + keys := make([]string, 0, len(m)) + + for k := range m { + keys = append(keys, k) + } + + sort.Strings(keys) + + for _, k := range keys { + if err := e.EncodeString(k); err != nil { + return err + } + if err := e.Encode(m[k]); err != nil { + return err + } + } + + return nil +} + +func (e *Encoder) encodeSortedMapStringString(m map[string]string) error { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + err := e.EncodeString(k) + if err != nil { + return err + } + if err = e.EncodeString(m[k]); err != nil { + return err + } + } + + return nil +} + +func (e *Encoder) EncodeMapLen(l int) error { + if l < 16 { + return e.writeCode(msgpcode.FixedMapLow | byte(l)) + } + if l <= math.MaxUint16 { + return e.write2(msgpcode.Map16, uint16(l)) + } + return e.write4(msgpcode.Map32, uint32(l)) +} + +func encodeStructValue(e *Encoder, strct reflect.Value) error { + structFields := structs.Fields(strct.Type(), e.structTag) + if e.flags&arrayEncodedStructsFlag != 0 || structFields.AsArray { + return encodeStructValueAsArray(e, strct, structFields.List) + } + fields := structFields.OmitEmpty(strct, e.flags&omitEmptyFlag != 0) + + if err := e.EncodeMapLen(len(fields)); err != nil { + return err + } + + for _, f := range fields { + if err := e.EncodeString(f.name); err != nil { + return err + } + if err := f.EncodeValue(e, strct); err != nil { + return err + } + } + + return nil +} + +func encodeStructValueAsArray(e *Encoder, strct reflect.Value, fields []*field) error { + if err := e.EncodeArrayLen(len(fields)); err != nil { + return err + } + for _, f := range fields { + if err := f.EncodeValue(e, strct); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/encode_number.go b/vendor/github.com/vmihailenco/msgpack/v5/encode_number.go new file mode 100644 index 000000000..63c311bfa --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/encode_number.go @@ -0,0 +1,252 @@ +package msgpack + +import ( + "math" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +// EncodeUint8 encodes an uint8 in 2 bytes preserving type of the number. +func (e *Encoder) EncodeUint8(n uint8) error { + return e.write1(msgpcode.Uint8, n) +} + +func (e *Encoder) encodeUint8Cond(n uint8) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeUint(uint64(n)) + } + return e.EncodeUint8(n) +} + +// EncodeUint16 encodes an uint16 in 3 bytes preserving type of the number. +func (e *Encoder) EncodeUint16(n uint16) error { + return e.write2(msgpcode.Uint16, n) +} + +func (e *Encoder) encodeUint16Cond(n uint16) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeUint(uint64(n)) + } + return e.EncodeUint16(n) +} + +// EncodeUint32 encodes an uint16 in 5 bytes preserving type of the number. +func (e *Encoder) EncodeUint32(n uint32) error { + return e.write4(msgpcode.Uint32, n) +} + +func (e *Encoder) encodeUint32Cond(n uint32) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeUint(uint64(n)) + } + return e.EncodeUint32(n) +} + +// EncodeUint64 encodes an uint16 in 9 bytes preserving type of the number. +func (e *Encoder) EncodeUint64(n uint64) error { + return e.write8(msgpcode.Uint64, n) +} + +func (e *Encoder) encodeUint64Cond(n uint64) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeUint(n) + } + return e.EncodeUint64(n) +} + +// EncodeInt8 encodes an int8 in 2 bytes preserving type of the number. +func (e *Encoder) EncodeInt8(n int8) error { + return e.write1(msgpcode.Int8, uint8(n)) +} + +func (e *Encoder) encodeInt8Cond(n int8) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeInt(int64(n)) + } + return e.EncodeInt8(n) +} + +// EncodeInt16 encodes an int16 in 3 bytes preserving type of the number. +func (e *Encoder) EncodeInt16(n int16) error { + return e.write2(msgpcode.Int16, uint16(n)) +} + +func (e *Encoder) encodeInt16Cond(n int16) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeInt(int64(n)) + } + return e.EncodeInt16(n) +} + +// EncodeInt32 encodes an int32 in 5 bytes preserving type of the number. +func (e *Encoder) EncodeInt32(n int32) error { + return e.write4(msgpcode.Int32, uint32(n)) +} + +func (e *Encoder) encodeInt32Cond(n int32) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeInt(int64(n)) + } + return e.EncodeInt32(n) +} + +// EncodeInt64 encodes an int64 in 9 bytes preserving type of the number. +func (e *Encoder) EncodeInt64(n int64) error { + return e.write8(msgpcode.Int64, uint64(n)) +} + +func (e *Encoder) encodeInt64Cond(n int64) error { + if e.flags&useCompactIntsFlag != 0 { + return e.EncodeInt(n) + } + return e.EncodeInt64(n) +} + +// EncodeUnsignedNumber encodes an uint64 in 1, 2, 3, 5, or 9 bytes. +// Type of the number is lost during encoding. +func (e *Encoder) EncodeUint(n uint64) error { + if n <= math.MaxInt8 { + return e.w.WriteByte(byte(n)) + } + if n <= math.MaxUint8 { + return e.EncodeUint8(uint8(n)) + } + if n <= math.MaxUint16 { + return e.EncodeUint16(uint16(n)) + } + if n <= math.MaxUint32 { + return e.EncodeUint32(uint32(n)) + } + return e.EncodeUint64(n) +} + +// EncodeNumber encodes an int64 in 1, 2, 3, 5, or 9 bytes. +// Type of the number is lost during encoding. +func (e *Encoder) EncodeInt(n int64) error { + if n >= 0 { + return e.EncodeUint(uint64(n)) + } + if n >= int64(int8(msgpcode.NegFixedNumLow)) { + return e.w.WriteByte(byte(n)) + } + if n >= math.MinInt8 { + return e.EncodeInt8(int8(n)) + } + if n >= math.MinInt16 { + return e.EncodeInt16(int16(n)) + } + if n >= math.MinInt32 { + return e.EncodeInt32(int32(n)) + } + return e.EncodeInt64(n) +} + +func (e *Encoder) EncodeFloat32(n float32) error { + if e.flags&useCompactFloatsFlag != 0 { + if float32(int64(n)) == n { + return e.EncodeInt(int64(n)) + } + } + return e.write4(msgpcode.Float, math.Float32bits(n)) +} + +func (e *Encoder) EncodeFloat64(n float64) error { + if e.flags&useCompactFloatsFlag != 0 { + // Both NaN and Inf convert to int64(-0x8000000000000000) + // If n is NaN then it never compares true with any other value + // If n is Inf then it doesn't convert from int64 back to +/-Inf + // In both cases the comparison works. + if float64(int64(n)) == n { + return e.EncodeInt(int64(n)) + } + } + return e.write8(msgpcode.Double, math.Float64bits(n)) +} + +func (e *Encoder) write1(code byte, n uint8) error { + e.buf = e.buf[:2] + e.buf[0] = code + e.buf[1] = n + return e.write(e.buf) +} + +func (e *Encoder) write2(code byte, n uint16) error { + e.buf = e.buf[:3] + e.buf[0] = code + e.buf[1] = byte(n >> 8) + e.buf[2] = byte(n) + return e.write(e.buf) +} + +func (e *Encoder) write4(code byte, n uint32) error { + e.buf = e.buf[:5] + e.buf[0] = code + e.buf[1] = byte(n >> 24) + e.buf[2] = byte(n >> 16) + e.buf[3] = byte(n >> 8) + e.buf[4] = byte(n) + return e.write(e.buf) +} + +func (e *Encoder) write8(code byte, n uint64) error { + e.buf = e.buf[:9] + e.buf[0] = code + e.buf[1] = byte(n >> 56) + e.buf[2] = byte(n >> 48) + e.buf[3] = byte(n >> 40) + e.buf[4] = byte(n >> 32) + e.buf[5] = byte(n >> 24) + e.buf[6] = byte(n >> 16) + e.buf[7] = byte(n >> 8) + e.buf[8] = byte(n) + return e.write(e.buf) +} + +func encodeUintValue(e *Encoder, v reflect.Value) error { + return e.EncodeUint(v.Uint()) +} + +func encodeIntValue(e *Encoder, v reflect.Value) error { + return e.EncodeInt(v.Int()) +} + +func encodeUint8CondValue(e *Encoder, v reflect.Value) error { + return e.encodeUint8Cond(uint8(v.Uint())) +} + +func encodeUint16CondValue(e *Encoder, v reflect.Value) error { + return e.encodeUint16Cond(uint16(v.Uint())) +} + +func encodeUint32CondValue(e *Encoder, v reflect.Value) error { + return e.encodeUint32Cond(uint32(v.Uint())) +} + +func encodeUint64CondValue(e *Encoder, v reflect.Value) error { + return e.encodeUint64Cond(v.Uint()) +} + +func encodeInt8CondValue(e *Encoder, v reflect.Value) error { + return e.encodeInt8Cond(int8(v.Int())) +} + +func encodeInt16CondValue(e *Encoder, v reflect.Value) error { + return e.encodeInt16Cond(int16(v.Int())) +} + +func encodeInt32CondValue(e *Encoder, v reflect.Value) error { + return e.encodeInt32Cond(int32(v.Int())) +} + +func encodeInt64CondValue(e *Encoder, v reflect.Value) error { + return e.encodeInt64Cond(v.Int()) +} + +func encodeFloat32Value(e *Encoder, v reflect.Value) error { + return e.EncodeFloat32(float32(v.Float())) +} + +func encodeFloat64Value(e *Encoder, v reflect.Value) error { + return e.EncodeFloat64(v.Float()) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/encode_slice.go b/vendor/github.com/vmihailenco/msgpack/v5/encode_slice.go new file mode 100644 index 000000000..ca46eadae --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/encode_slice.go @@ -0,0 +1,139 @@ +package msgpack + +import ( + "math" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +var stringSliceType = reflect.TypeOf(([]string)(nil)) + +func encodeStringValue(e *Encoder, v reflect.Value) error { + return e.EncodeString(v.String()) +} + +func encodeByteSliceValue(e *Encoder, v reflect.Value) error { + return e.EncodeBytes(v.Bytes()) +} + +func encodeByteArrayValue(e *Encoder, v reflect.Value) error { + if err := e.EncodeBytesLen(v.Len()); err != nil { + return err + } + + if v.CanAddr() { + b := v.Slice(0, v.Len()).Bytes() + return e.write(b) + } + + e.buf = grow(e.buf, v.Len()) + reflect.Copy(reflect.ValueOf(e.buf), v) + return e.write(e.buf) +} + +func grow(b []byte, n int) []byte { + if cap(b) >= n { + return b[:n] + } + b = b[:cap(b)] + b = append(b, make([]byte, n-len(b))...) + return b +} + +func (e *Encoder) EncodeBytesLen(l int) error { + if l < 256 { + return e.write1(msgpcode.Bin8, uint8(l)) + } + if l <= math.MaxUint16 { + return e.write2(msgpcode.Bin16, uint16(l)) + } + return e.write4(msgpcode.Bin32, uint32(l)) +} + +func (e *Encoder) encodeStringLen(l int) error { + if l < 32 { + return e.writeCode(msgpcode.FixedStrLow | byte(l)) + } + if l < 256 { + return e.write1(msgpcode.Str8, uint8(l)) + } + if l <= math.MaxUint16 { + return e.write2(msgpcode.Str16, uint16(l)) + } + return e.write4(msgpcode.Str32, uint32(l)) +} + +func (e *Encoder) EncodeString(v string) error { + if intern := e.flags&useInternedStringsFlag != 0; intern || len(e.dict) > 0 { + return e.encodeInternedString(v, intern) + } + return e.encodeNormalString(v) +} + +func (e *Encoder) encodeNormalString(v string) error { + if err := e.encodeStringLen(len(v)); err != nil { + return err + } + return e.writeString(v) +} + +func (e *Encoder) EncodeBytes(v []byte) error { + if v == nil { + return e.EncodeNil() + } + if err := e.EncodeBytesLen(len(v)); err != nil { + return err + } + return e.write(v) +} + +func (e *Encoder) EncodeArrayLen(l int) error { + if l < 16 { + return e.writeCode(msgpcode.FixedArrayLow | byte(l)) + } + if l <= math.MaxUint16 { + return e.write2(msgpcode.Array16, uint16(l)) + } + return e.write4(msgpcode.Array32, uint32(l)) +} + +func encodeStringSliceValue(e *Encoder, v reflect.Value) error { + ss := v.Convert(stringSliceType).Interface().([]string) + return e.encodeStringSlice(ss) +} + +func (e *Encoder) encodeStringSlice(s []string) error { + if s == nil { + return e.EncodeNil() + } + if err := e.EncodeArrayLen(len(s)); err != nil { + return err + } + for _, v := range s { + if err := e.EncodeString(v); err != nil { + return err + } + } + return nil +} + +func encodeSliceValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + return encodeArrayValue(e, v) +} + +func encodeArrayValue(e *Encoder, v reflect.Value) error { + l := v.Len() + if err := e.EncodeArrayLen(l); err != nil { + return err + } + for i := 0; i < l; i++ { + if err := e.EncodeValue(v.Index(i)); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/encode_value.go b/vendor/github.com/vmihailenco/msgpack/v5/encode_value.go new file mode 100644 index 000000000..48cf489fa --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/encode_value.go @@ -0,0 +1,245 @@ +package msgpack + +import ( + "encoding" + "fmt" + "reflect" +) + +var valueEncoders []encoderFunc + +//nolint:gochecknoinits +func init() { + valueEncoders = []encoderFunc{ + reflect.Bool: encodeBoolValue, + reflect.Int: encodeIntValue, + reflect.Int8: encodeInt8CondValue, + reflect.Int16: encodeInt16CondValue, + reflect.Int32: encodeInt32CondValue, + reflect.Int64: encodeInt64CondValue, + reflect.Uint: encodeUintValue, + reflect.Uint8: encodeUint8CondValue, + reflect.Uint16: encodeUint16CondValue, + reflect.Uint32: encodeUint32CondValue, + reflect.Uint64: encodeUint64CondValue, + reflect.Float32: encodeFloat32Value, + reflect.Float64: encodeFloat64Value, + reflect.Complex64: encodeUnsupportedValue, + reflect.Complex128: encodeUnsupportedValue, + reflect.Array: encodeArrayValue, + reflect.Chan: encodeUnsupportedValue, + reflect.Func: encodeUnsupportedValue, + reflect.Interface: encodeInterfaceValue, + reflect.Map: encodeMapValue, + reflect.Ptr: encodeUnsupportedValue, + reflect.Slice: encodeSliceValue, + reflect.String: encodeStringValue, + reflect.Struct: encodeStructValue, + reflect.UnsafePointer: encodeUnsupportedValue, + } +} + +func getEncoder(typ reflect.Type) encoderFunc { + if v, ok := typeEncMap.Load(typ); ok { + return v.(encoderFunc) + } + fn := _getEncoder(typ) + typeEncMap.Store(typ, fn) + return fn +} + +func _getEncoder(typ reflect.Type) encoderFunc { + kind := typ.Kind() + + if kind == reflect.Ptr { + if _, ok := typeEncMap.Load(typ.Elem()); ok { + return ptrEncoderFunc(typ) + } + } + + if typ.Implements(customEncoderType) { + return encodeCustomValue + } + if typ.Implements(marshalerType) { + return marshalValue + } + if typ.Implements(binaryMarshalerType) { + return marshalBinaryValue + } + if typ.Implements(textMarshalerType) { + return marshalTextValue + } + + // Addressable struct field value. + if kind != reflect.Ptr { + ptr := reflect.PtrTo(typ) + if ptr.Implements(customEncoderType) { + return encodeCustomValuePtr + } + if ptr.Implements(marshalerType) { + return marshalValuePtr + } + if ptr.Implements(binaryMarshalerType) { + return marshalBinaryValueAddr + } + if ptr.Implements(textMarshalerType) { + return marshalTextValueAddr + } + } + + if typ == errorType { + return encodeErrorValue + } + + switch kind { + case reflect.Ptr: + return ptrEncoderFunc(typ) + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + return encodeByteSliceValue + } + if elem == stringType { + return encodeStringSliceValue + } + case reflect.Array: + if typ.Elem().Kind() == reflect.Uint8 { + return encodeByteArrayValue + } + case reflect.Map: + if typ.Key() == stringType { + switch typ.Elem() { + case stringType: + return encodeMapStringStringValue + case interfaceType: + return encodeMapStringInterfaceValue + } + } + } + + return valueEncoders[kind] +} + +func ptrEncoderFunc(typ reflect.Type) encoderFunc { + encoder := getEncoder(typ.Elem()) + return func(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + return encoder(e, v.Elem()) + } +} + +func encodeCustomValuePtr(e *Encoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) + } + encoder := v.Addr().Interface().(CustomEncoder) + return encoder.EncodeMsgpack(e) +} + +func encodeCustomValue(e *Encoder, v reflect.Value) error { + if nilable(v.Kind()) && v.IsNil() { + return e.EncodeNil() + } + + encoder := v.Interface().(CustomEncoder) + return encoder.EncodeMsgpack(e) +} + +func marshalValuePtr(e *Encoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) + } + return marshalValue(e, v.Addr()) +} + +func marshalValue(e *Encoder, v reflect.Value) error { + if nilable(v.Kind()) && v.IsNil() { + return e.EncodeNil() + } + + marshaler := v.Interface().(Marshaler) + b, err := marshaler.MarshalMsgpack() + if err != nil { + return err + } + _, err = e.w.Write(b) + return err +} + +func encodeBoolValue(e *Encoder, v reflect.Value) error { + return e.EncodeBool(v.Bool()) +} + +func encodeInterfaceValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + return e.EncodeValue(v.Elem()) +} + +func encodeErrorValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + return e.EncodeString(v.Interface().(error).Error()) +} + +func encodeUnsupportedValue(e *Encoder, v reflect.Value) error { + return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type()) +} + +func nilable(kind reflect.Kind) bool { + switch kind { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return true + } + return false +} + +//------------------------------------------------------------------------------ + +func marshalBinaryValueAddr(e *Encoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) + } + return marshalBinaryValue(e, v.Addr()) +} + +func marshalBinaryValue(e *Encoder, v reflect.Value) error { + if nilable(v.Kind()) && v.IsNil() { + return e.EncodeNil() + } + + marshaler := v.Interface().(encoding.BinaryMarshaler) + data, err := marshaler.MarshalBinary() + if err != nil { + return err + } + + return e.EncodeBytes(data) +} + +//------------------------------------------------------------------------------ + +func marshalTextValueAddr(e *Encoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) + } + return marshalTextValue(e, v.Addr()) +} + +func marshalTextValue(e *Encoder, v reflect.Value) error { + if nilable(v.Kind()) && v.IsNil() { + return e.EncodeNil() + } + + marshaler := v.Interface().(encoding.TextMarshaler) + data, err := marshaler.MarshalText() + if err != nil { + return err + } + + return e.EncodeBytes(data) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/ext.go b/vendor/github.com/vmihailenco/msgpack/v5/ext.go new file mode 100644 index 000000000..76e11603d --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/ext.go @@ -0,0 +1,303 @@ +package msgpack + +import ( + "fmt" + "math" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type extInfo struct { + Type reflect.Type + Decoder func(d *Decoder, v reflect.Value, extLen int) error +} + +var extTypes = make(map[int8]*extInfo) + +type MarshalerUnmarshaler interface { + Marshaler + Unmarshaler +} + +func RegisterExt(extID int8, value MarshalerUnmarshaler) { + RegisterExtEncoder(extID, value, func(e *Encoder, v reflect.Value) ([]byte, error) { + marshaler := v.Interface().(Marshaler) + return marshaler.MarshalMsgpack() + }) + RegisterExtDecoder(extID, value, func(d *Decoder, v reflect.Value, extLen int) error { + b, err := d.readN(extLen) + if err != nil { + return err + } + return v.Interface().(Unmarshaler).UnmarshalMsgpack(b) + }) +} + +func UnregisterExt(extID int8) { + unregisterExtEncoder(extID) + unregisterExtDecoder(extID) +} + +func RegisterExtEncoder( + extID int8, + value interface{}, + encoder func(enc *Encoder, v reflect.Value) ([]byte, error), +) { + unregisterExtEncoder(extID) + + typ := reflect.TypeOf(value) + extEncoder := makeExtEncoder(extID, typ, encoder) + typeEncMap.Store(extID, typ) + typeEncMap.Store(typ, extEncoder) + if typ.Kind() == reflect.Ptr { + typeEncMap.Store(typ.Elem(), makeExtEncoderAddr(extEncoder)) + } +} + +func unregisterExtEncoder(extID int8) { + t, ok := typeEncMap.Load(extID) + if !ok { + return + } + typeEncMap.Delete(extID) + typ := t.(reflect.Type) + typeEncMap.Delete(typ) + if typ.Kind() == reflect.Ptr { + typeEncMap.Delete(typ.Elem()) + } +} + +func makeExtEncoder( + extID int8, + typ reflect.Type, + encoder func(enc *Encoder, v reflect.Value) ([]byte, error), +) encoderFunc { + nilable := typ.Kind() == reflect.Ptr + + return func(e *Encoder, v reflect.Value) error { + if nilable && v.IsNil() { + return e.EncodeNil() + } + + b, err := encoder(e, v) + if err != nil { + return err + } + + if err := e.EncodeExtHeader(extID, len(b)); err != nil { + return err + } + + return e.write(b) + } +} + +func makeExtEncoderAddr(extEncoder encoderFunc) encoderFunc { + return func(e *Encoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface()) + } + return extEncoder(e, v.Addr()) + } +} + +func RegisterExtDecoder( + extID int8, + value interface{}, + decoder func(dec *Decoder, v reflect.Value, extLen int) error, +) { + unregisterExtDecoder(extID) + + typ := reflect.TypeOf(value) + extDecoder := makeExtDecoder(extID, typ, decoder) + extTypes[extID] = &extInfo{ + Type: typ, + Decoder: decoder, + } + + typeDecMap.Store(extID, typ) + typeDecMap.Store(typ, extDecoder) + if typ.Kind() == reflect.Ptr { + typeDecMap.Store(typ.Elem(), makeExtDecoderAddr(extDecoder)) + } +} + +func unregisterExtDecoder(extID int8) { + t, ok := typeDecMap.Load(extID) + if !ok { + return + } + typeDecMap.Delete(extID) + delete(extTypes, extID) + typ := t.(reflect.Type) + typeDecMap.Delete(typ) + if typ.Kind() == reflect.Ptr { + typeDecMap.Delete(typ.Elem()) + } +} + +func makeExtDecoder( + wantedExtID int8, + typ reflect.Type, + decoder func(d *Decoder, v reflect.Value, extLen int) error, +) decoderFunc { + return nilAwareDecoder(typ, func(d *Decoder, v reflect.Value) error { + extID, extLen, err := d.DecodeExtHeader() + if err != nil { + return err + } + if extID != wantedExtID { + return fmt.Errorf("msgpack: got ext type=%d, wanted %d", extID, wantedExtID) + } + return decoder(d, v, extLen) + }) +} + +func makeExtDecoderAddr(extDecoder decoderFunc) decoderFunc { + return func(d *Decoder, v reflect.Value) error { + if !v.CanAddr() { + return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface()) + } + return extDecoder(d, v.Addr()) + } +} + +func (e *Encoder) EncodeExtHeader(extID int8, extLen int) error { + if err := e.encodeExtLen(extLen); err != nil { + return err + } + if err := e.w.WriteByte(byte(extID)); err != nil { + return err + } + return nil +} + +func (e *Encoder) encodeExtLen(l int) error { + switch l { + case 1: + return e.writeCode(msgpcode.FixExt1) + case 2: + return e.writeCode(msgpcode.FixExt2) + case 4: + return e.writeCode(msgpcode.FixExt4) + case 8: + return e.writeCode(msgpcode.FixExt8) + case 16: + return e.writeCode(msgpcode.FixExt16) + } + if l <= math.MaxUint8 { + return e.write1(msgpcode.Ext8, uint8(l)) + } + if l <= math.MaxUint16 { + return e.write2(msgpcode.Ext16, uint16(l)) + } + return e.write4(msgpcode.Ext32, uint32(l)) +} + +func (d *Decoder) DecodeExtHeader() (extID int8, extLen int, err error) { + c, err := d.readCode() + if err != nil { + return + } + return d.extHeader(c) +} + +func (d *Decoder) extHeader(c byte) (int8, int, error) { + extLen, err := d.parseExtLen(c) + if err != nil { + return 0, 0, err + } + + extID, err := d.readCode() + if err != nil { + return 0, 0, err + } + + return int8(extID), extLen, nil +} + +func (d *Decoder) parseExtLen(c byte) (int, error) { + switch c { + case msgpcode.FixExt1: + return 1, nil + case msgpcode.FixExt2: + return 2, nil + case msgpcode.FixExt4: + return 4, nil + case msgpcode.FixExt8: + return 8, nil + case msgpcode.FixExt16: + return 16, nil + case msgpcode.Ext8: + n, err := d.uint8() + return int(n), err + case msgpcode.Ext16: + n, err := d.uint16() + return int(n), err + case msgpcode.Ext32: + n, err := d.uint32() + return int(n), err + default: + return 0, fmt.Errorf("msgpack: invalid code=%x decoding ext len", c) + } +} + +func (d *Decoder) decodeInterfaceExt(c byte) (interface{}, error) { + extID, extLen, err := d.extHeader(c) + if err != nil { + return nil, err + } + + info, ok := extTypes[extID] + if !ok { + return nil, fmt.Errorf("msgpack: unknown ext id=%d", extID) + } + + v := reflect.New(info.Type).Elem() + if nilable(v.Kind()) && v.IsNil() { + v.Set(reflect.New(info.Type.Elem())) + } + + if err := info.Decoder(d, v, extLen); err != nil { + return nil, err + } + + return v.Interface(), nil +} + +func (d *Decoder) skipExt(c byte) error { + n, err := d.parseExtLen(c) + if err != nil { + return err + } + return d.skipN(n + 1) +} + +func (d *Decoder) skipExtHeader(c byte) error { + // Read ext type. + _, err := d.readCode() + if err != nil { + return err + } + // Read ext body len. + for i := 0; i < extHeaderLen(c); i++ { + _, err := d.readCode() + if err != nil { + return err + } + } + return nil +} + +func extHeaderLen(c byte) int { + switch c { + case msgpcode.Ext8: + return 1 + case msgpcode.Ext16: + return 2 + case msgpcode.Ext32: + return 4 + } + return 0 +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/intern.go b/vendor/github.com/vmihailenco/msgpack/v5/intern.go new file mode 100644 index 000000000..be0316a83 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/intern.go @@ -0,0 +1,238 @@ +package msgpack + +import ( + "fmt" + "math" + "reflect" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +const ( + minInternedStringLen = 3 + maxDictLen = math.MaxUint16 +) + +var internedStringExtID = int8(math.MinInt8) + +func init() { + extTypes[internedStringExtID] = &extInfo{ + Type: stringType, + Decoder: decodeInternedStringExt, + } +} + +func decodeInternedStringExt(d *Decoder, v reflect.Value, extLen int) error { + idx, err := d.decodeInternedStringIndex(extLen) + if err != nil { + return err + } + + s, err := d.internedStringAtIndex(idx) + if err != nil { + return err + } + + v.SetString(s) + return nil +} + +//------------------------------------------------------------------------------ + +func encodeInternedInterfaceValue(e *Encoder, v reflect.Value) error { + if v.IsNil() { + return e.EncodeNil() + } + + v = v.Elem() + if v.Kind() == reflect.String { + return e.encodeInternedString(v.String(), true) + } + return e.EncodeValue(v) +} + +func encodeInternedStringValue(e *Encoder, v reflect.Value) error { + return e.encodeInternedString(v.String(), true) +} + +func (e *Encoder) encodeInternedString(s string, intern bool) error { + // Interned string takes at least 3 bytes. Plain string 1 byte + string len. + if len(s) >= minInternedStringLen { + if idx, ok := e.dict[s]; ok { + return e.encodeInternedStringIndex(idx) + } + + if intern && len(e.dict) < maxDictLen { + if e.dict == nil { + e.dict = make(map[string]int) + } + idx := len(e.dict) + e.dict[s] = idx + } + } + + return e.encodeNormalString(s) +} + +func (e *Encoder) encodeInternedStringIndex(idx int) error { + if idx <= math.MaxUint8 { + if err := e.writeCode(msgpcode.FixExt1); err != nil { + return err + } + return e.write1(byte(internedStringExtID), uint8(idx)) + } + + if idx <= math.MaxUint16 { + if err := e.writeCode(msgpcode.FixExt2); err != nil { + return err + } + return e.write2(byte(internedStringExtID), uint16(idx)) + } + + if uint64(idx) <= math.MaxUint32 { + if err := e.writeCode(msgpcode.FixExt4); err != nil { + return err + } + return e.write4(byte(internedStringExtID), uint32(idx)) + } + + return fmt.Errorf("msgpack: interned string index=%d is too large", idx) +} + +//------------------------------------------------------------------------------ + +func decodeInternedInterfaceValue(d *Decoder, v reflect.Value) error { + s, err := d.decodeInternedString(true) + if err == nil { + v.Set(reflect.ValueOf(s)) + return nil + } + if err != nil { + if _, ok := err.(unexpectedCodeError); !ok { + return err + } + } + + if err := d.s.UnreadByte(); err != nil { + return err + } + return decodeInterfaceValue(d, v) +} + +func decodeInternedStringValue(d *Decoder, v reflect.Value) error { + s, err := d.decodeInternedString(true) + if err != nil { + return err + } + + v.SetString(s) + return nil +} + +func (d *Decoder) decodeInternedString(intern bool) (string, error) { + c, err := d.readCode() + if err != nil { + return "", err + } + + if msgpcode.IsFixedString(c) { + n := int(c & msgpcode.FixedStrMask) + return d.decodeInternedStringWithLen(n, intern) + } + + switch c { + case msgpcode.Nil: + return "", nil + case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4: + typeID, extLen, err := d.extHeader(c) + if err != nil { + return "", err + } + if typeID != internedStringExtID { + err := fmt.Errorf("msgpack: got ext type=%d, wanted %d", + typeID, internedStringExtID) + return "", err + } + + idx, err := d.decodeInternedStringIndex(extLen) + if err != nil { + return "", err + } + + return d.internedStringAtIndex(idx) + case msgpcode.Str8, msgpcode.Bin8: + n, err := d.uint8() + if err != nil { + return "", err + } + return d.decodeInternedStringWithLen(int(n), intern) + case msgpcode.Str16, msgpcode.Bin16: + n, err := d.uint16() + if err != nil { + return "", err + } + return d.decodeInternedStringWithLen(int(n), intern) + case msgpcode.Str32, msgpcode.Bin32: + n, err := d.uint32() + if err != nil { + return "", err + } + return d.decodeInternedStringWithLen(int(n), intern) + } + + return "", unexpectedCodeError{ + code: c, + hint: "interned string", + } +} + +func (d *Decoder) decodeInternedStringIndex(extLen int) (int, error) { + switch extLen { + case 1: + n, err := d.uint8() + if err != nil { + return 0, err + } + return int(n), nil + case 2: + n, err := d.uint16() + if err != nil { + return 0, err + } + return int(n), nil + case 4: + n, err := d.uint32() + if err != nil { + return 0, err + } + return int(n), nil + } + + err := fmt.Errorf("msgpack: unsupported ext len=%d decoding interned string", extLen) + return 0, err +} + +func (d *Decoder) internedStringAtIndex(idx int) (string, error) { + if idx >= len(d.dict) { + err := fmt.Errorf("msgpack: interned string at index=%d does not exist", idx) + return "", err + } + return d.dict[idx], nil +} + +func (d *Decoder) decodeInternedStringWithLen(n int, intern bool) (string, error) { + if n <= 0 { + return "", nil + } + + s, err := d.stringWithLen(n) + if err != nil { + return "", err + } + + if intern && len(s) >= minInternedStringLen && len(d.dict) < maxDictLen { + d.dict = append(d.dict, s) + } + + return s, nil +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/msgpack.go b/vendor/github.com/vmihailenco/msgpack/v5/msgpack.go new file mode 100644 index 000000000..4db2fa2c7 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/msgpack.go @@ -0,0 +1,52 @@ +package msgpack + +import "fmt" + +type Marshaler interface { + MarshalMsgpack() ([]byte, error) +} + +type Unmarshaler interface { + UnmarshalMsgpack([]byte) error +} + +type CustomEncoder interface { + EncodeMsgpack(*Encoder) error +} + +type CustomDecoder interface { + DecodeMsgpack(*Decoder) error +} + +//------------------------------------------------------------------------------ + +type RawMessage []byte + +var ( + _ CustomEncoder = (RawMessage)(nil) + _ CustomDecoder = (*RawMessage)(nil) +) + +func (m RawMessage) EncodeMsgpack(enc *Encoder) error { + return enc.write(m) +} + +func (m *RawMessage) DecodeMsgpack(dec *Decoder) error { + msg, err := dec.DecodeRaw() + if err != nil { + return err + } + *m = msg + return nil +} + +//------------------------------------------------------------------------------ + +type unexpectedCodeError struct { + code byte + hint string +} + +func (err unexpectedCodeError) Error() string { + return fmt.Sprintf("msgpack: unexpected code=%x decoding %s", err.code, err.hint) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/msgpcode/msgpcode.go b/vendor/github.com/vmihailenco/msgpack/v5/msgpcode/msgpcode.go new file mode 100644 index 000000000..e35389ccc --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/msgpcode/msgpcode.go @@ -0,0 +1,88 @@ +package msgpcode + +var ( + PosFixedNumHigh byte = 0x7f + NegFixedNumLow byte = 0xe0 + + Nil byte = 0xc0 + + False byte = 0xc2 + True byte = 0xc3 + + Float byte = 0xca + Double byte = 0xcb + + Uint8 byte = 0xcc + Uint16 byte = 0xcd + Uint32 byte = 0xce + Uint64 byte = 0xcf + + Int8 byte = 0xd0 + Int16 byte = 0xd1 + Int32 byte = 0xd2 + Int64 byte = 0xd3 + + FixedStrLow byte = 0xa0 + FixedStrHigh byte = 0xbf + FixedStrMask byte = 0x1f + Str8 byte = 0xd9 + Str16 byte = 0xda + Str32 byte = 0xdb + + Bin8 byte = 0xc4 + Bin16 byte = 0xc5 + Bin32 byte = 0xc6 + + FixedArrayLow byte = 0x90 + FixedArrayHigh byte = 0x9f + FixedArrayMask byte = 0xf + Array16 byte = 0xdc + Array32 byte = 0xdd + + FixedMapLow byte = 0x80 + FixedMapHigh byte = 0x8f + FixedMapMask byte = 0xf + Map16 byte = 0xde + Map32 byte = 0xdf + + FixExt1 byte = 0xd4 + FixExt2 byte = 0xd5 + FixExt4 byte = 0xd6 + FixExt8 byte = 0xd7 + FixExt16 byte = 0xd8 + Ext8 byte = 0xc7 + Ext16 byte = 0xc8 + Ext32 byte = 0xc9 +) + +func IsFixedNum(c byte) bool { + return c <= PosFixedNumHigh || c >= NegFixedNumLow +} + +func IsFixedMap(c byte) bool { + return c >= FixedMapLow && c <= FixedMapHigh +} + +func IsFixedArray(c byte) bool { + return c >= FixedArrayLow && c <= FixedArrayHigh +} + +func IsFixedString(c byte) bool { + return c >= FixedStrLow && c <= FixedStrHigh +} + +func IsString(c byte) bool { + return IsFixedString(c) || c == Str8 || c == Str16 || c == Str32 +} + +func IsBin(c byte) bool { + return c == Bin8 || c == Bin16 || c == Bin32 +} + +func IsFixedExt(c byte) bool { + return c >= FixExt1 && c <= FixExt16 +} + +func IsExt(c byte) bool { + return IsFixedExt(c) || c == Ext8 || c == Ext16 || c == Ext32 +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/safe.go b/vendor/github.com/vmihailenco/msgpack/v5/safe.go new file mode 100644 index 000000000..8352c9dce --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/safe.go @@ -0,0 +1,13 @@ +// +build appengine + +package msgpack + +// bytesToString converts byte slice to string. +func bytesToString(b []byte) string { + return string(b) +} + +// stringToBytes converts string to byte slice. +func stringToBytes(s string) []byte { + return []byte(s) +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/time.go b/vendor/github.com/vmihailenco/msgpack/v5/time.go new file mode 100644 index 000000000..44566ec07 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/time.go @@ -0,0 +1,145 @@ +package msgpack + +import ( + "encoding/binary" + "fmt" + "reflect" + "time" + + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +var timeExtID int8 = -1 + +func init() { + RegisterExtEncoder(timeExtID, time.Time{}, timeEncoder) + RegisterExtDecoder(timeExtID, time.Time{}, timeDecoder) +} + +func timeEncoder(e *Encoder, v reflect.Value) ([]byte, error) { + return e.encodeTime(v.Interface().(time.Time)), nil +} + +func timeDecoder(d *Decoder, v reflect.Value, extLen int) error { + tm, err := d.decodeTime(extLen) + if err != nil { + return err + } + + ptr := v.Addr().Interface().(*time.Time) + *ptr = tm + + return nil +} + +func (e *Encoder) EncodeTime(tm time.Time) error { + b := e.encodeTime(tm) + if err := e.encodeExtLen(len(b)); err != nil { + return err + } + if err := e.w.WriteByte(byte(timeExtID)); err != nil { + return err + } + return e.write(b) +} + +func (e *Encoder) encodeTime(tm time.Time) []byte { + if e.timeBuf == nil { + e.timeBuf = make([]byte, 12) + } + + secs := uint64(tm.Unix()) + if secs>>34 == 0 { + data := uint64(tm.Nanosecond())<<34 | secs + + if data&0xffffffff00000000 == 0 { + b := e.timeBuf[:4] + binary.BigEndian.PutUint32(b, uint32(data)) + return b + } + + b := e.timeBuf[:8] + binary.BigEndian.PutUint64(b, data) + return b + } + + b := e.timeBuf[:12] + binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond())) + binary.BigEndian.PutUint64(b[4:], secs) + return b +} + +func (d *Decoder) DecodeTime() (time.Time, error) { + c, err := d.readCode() + if err != nil { + return time.Time{}, err + } + + // Legacy format. + if c == msgpcode.FixedArrayLow|2 { + sec, err := d.DecodeInt64() + if err != nil { + return time.Time{}, err + } + + nsec, err := d.DecodeInt64() + if err != nil { + return time.Time{}, err + } + + return time.Unix(sec, nsec), nil + } + + if msgpcode.IsString(c) { + s, err := d.string(c) + if err != nil { + return time.Time{}, err + } + return time.Parse(time.RFC3339Nano, s) + } + + extID, extLen, err := d.extHeader(c) + if err != nil { + return time.Time{}, err + } + + if extID != timeExtID { + return time.Time{}, fmt.Errorf("msgpack: invalid time ext id=%d", extID) + } + + tm, err := d.decodeTime(extLen) + if err != nil { + return tm, err + } + + if tm.IsZero() { + // Zero time does not have timezone information. + return tm.UTC(), nil + } + return tm, nil +} + +func (d *Decoder) decodeTime(extLen int) (time.Time, error) { + b, err := d.readN(extLen) + if err != nil { + return time.Time{}, err + } + + switch len(b) { + case 4: + sec := binary.BigEndian.Uint32(b) + return time.Unix(int64(sec), 0), nil + case 8: + sec := binary.BigEndian.Uint64(b) + nsec := int64(sec >> 34) + sec &= 0x00000003ffffffff + return time.Unix(int64(sec), nsec), nil + case 12: + nsec := binary.BigEndian.Uint32(b) + sec := binary.BigEndian.Uint64(b[4:]) + return time.Unix(int64(sec), int64(nsec)), nil + default: + err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen) + return time.Time{}, err + } +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/types.go b/vendor/github.com/vmihailenco/msgpack/v5/types.go new file mode 100644 index 000000000..69aca611b --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/types.go @@ -0,0 +1,407 @@ +package msgpack + +import ( + "encoding" + "fmt" + "log" + "reflect" + "sync" + + "github.com/vmihailenco/tagparser/v2" +) + +var errorType = reflect.TypeOf((*error)(nil)).Elem() + +var ( + customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem() + customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem() +) + +var ( + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +var ( + binaryMarshalerType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem() + binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() +) + +var ( + textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +) + +type ( + encoderFunc func(*Encoder, reflect.Value) error + decoderFunc func(*Decoder, reflect.Value) error +) + +var ( + typeEncMap sync.Map + typeDecMap sync.Map +) + +// Register registers encoder and decoder functions for a value. +// This is low level API and in most cases you should prefer implementing +// CustomEncoder/CustomDecoder or Marshaler/Unmarshaler interfaces. +func Register(value interface{}, enc encoderFunc, dec decoderFunc) { + typ := reflect.TypeOf(value) + if enc != nil { + typeEncMap.Store(typ, enc) + } + if dec != nil { + typeDecMap.Store(typ, dec) + } +} + +//------------------------------------------------------------------------------ + +const defaultStructTag = "msgpack" + +var structs = newStructCache() + +type structCache struct { + m sync.Map +} + +type structCacheKey struct { + tag string + typ reflect.Type +} + +func newStructCache() *structCache { + return new(structCache) +} + +func (m *structCache) Fields(typ reflect.Type, tag string) *fields { + key := structCacheKey{tag: tag, typ: typ} + + if v, ok := m.m.Load(key); ok { + return v.(*fields) + } + + fs := getFields(typ, tag) + m.m.Store(key, fs) + + return fs +} + +//------------------------------------------------------------------------------ + +type field struct { + name string + index []int + omitEmpty bool + encoder encoderFunc + decoder decoderFunc +} + +func (f *field) Omit(strct reflect.Value, forced bool) bool { + v, ok := fieldByIndex(strct, f.index) + if !ok { + return true + } + return (f.omitEmpty || forced) && isEmptyValue(v) +} + +func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error { + v, ok := fieldByIndex(strct, f.index) + if !ok { + return e.EncodeNil() + } + return f.encoder(e, v) +} + +func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error { + v := fieldByIndexAlloc(strct, f.index) + return f.decoder(d, v) +} + +//------------------------------------------------------------------------------ + +type fields struct { + Type reflect.Type + Map map[string]*field + List []*field + AsArray bool + + hasOmitEmpty bool +} + +func newFields(typ reflect.Type) *fields { + return &fields{ + Type: typ, + Map: make(map[string]*field, typ.NumField()), + List: make([]*field, 0, typ.NumField()), + } +} + +func (fs *fields) Add(field *field) { + fs.warnIfFieldExists(field.name) + fs.Map[field.name] = field + fs.List = append(fs.List, field) + if field.omitEmpty { + fs.hasOmitEmpty = true + } +} + +func (fs *fields) warnIfFieldExists(name string) { + if _, ok := fs.Map[name]; ok { + log.Printf("msgpack: %s already has field=%s", fs.Type, name) + } +} + +func (fs *fields) OmitEmpty(strct reflect.Value, forced bool) []*field { + if !fs.hasOmitEmpty && !forced { + return fs.List + } + + fields := make([]*field, 0, len(fs.List)) + + for _, f := range fs.List { + if !f.Omit(strct, forced) { + fields = append(fields, f) + } + } + + return fields +} + +func getFields(typ reflect.Type, fallbackTag string) *fields { + fs := newFields(typ) + + var omitEmpty bool + for i := 0; i < typ.NumField(); i++ { + f := typ.Field(i) + + tagStr := f.Tag.Get(defaultStructTag) + if tagStr == "" && fallbackTag != "" { + tagStr = f.Tag.Get(fallbackTag) + } + + tag := tagparser.Parse(tagStr) + if tag.Name == "-" { + continue + } + + if f.Name == "_msgpack" { + fs.AsArray = tag.HasOption("as_array") || tag.HasOption("asArray") + if tag.HasOption("omitempty") { + omitEmpty = true + } + } + + if f.PkgPath != "" && !f.Anonymous { + continue + } + + field := &field{ + name: tag.Name, + index: f.Index, + omitEmpty: omitEmpty || tag.HasOption("omitempty"), + } + + if tag.HasOption("intern") { + switch f.Type.Kind() { + case reflect.Interface: + field.encoder = encodeInternedInterfaceValue + field.decoder = decodeInternedInterfaceValue + case reflect.String: + field.encoder = encodeInternedStringValue + field.decoder = decodeInternedStringValue + default: + err := fmt.Errorf("msgpack: intern strings are not supported on %s", f.Type) + panic(err) + } + } else { + field.encoder = getEncoder(f.Type) + field.decoder = getDecoder(f.Type) + } + + if field.name == "" { + field.name = f.Name + } + + if f.Anonymous && !tag.HasOption("noinline") { + inline := tag.HasOption("inline") + if inline { + inlineFields(fs, f.Type, field, fallbackTag) + } else { + inline = shouldInline(fs, f.Type, field, fallbackTag) + } + + if inline { + if _, ok := fs.Map[field.name]; ok { + log.Printf("msgpack: %s already has field=%s", fs.Type, field.name) + } + fs.Map[field.name] = field + continue + } + } + + fs.Add(field) + + if alias, ok := tag.Options["alias"]; ok { + fs.warnIfFieldExists(alias) + fs.Map[alias] = field + } + } + return fs +} + +var ( + encodeStructValuePtr uintptr + decodeStructValuePtr uintptr +) + +//nolint:gochecknoinits +func init() { + encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer() + decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer() +} + +func inlineFields(fs *fields, typ reflect.Type, f *field, tag string) { + inlinedFields := getFields(typ, tag).List + for _, field := range inlinedFields { + if _, ok := fs.Map[field.name]; ok { + // Don't inline shadowed fields. + continue + } + field.index = append(f.index, field.index...) + fs.Add(field) + } +} + +func shouldInline(fs *fields, typ reflect.Type, f *field, tag string) bool { + var encoder encoderFunc + var decoder decoderFunc + + if typ.Kind() == reflect.Struct { + encoder = f.encoder + decoder = f.decoder + } else { + for typ.Kind() == reflect.Ptr { + typ = typ.Elem() + encoder = getEncoder(typ) + decoder = getDecoder(typ) + } + if typ.Kind() != reflect.Struct { + return false + } + } + + if reflect.ValueOf(encoder).Pointer() != encodeStructValuePtr { + return false + } + if reflect.ValueOf(decoder).Pointer() != decodeStructValuePtr { + return false + } + + inlinedFields := getFields(typ, tag).List + for _, field := range inlinedFields { + if _, ok := fs.Map[field.name]; ok { + // Don't auto inline if there are shadowed fields. + return false + } + } + + for _, field := range inlinedFields { + field.index = append(f.index, field.index...) + fs.Add(field) + } + return true +} + +type isZeroer interface { + IsZero() bool +} + +func isEmptyValue(v reflect.Value) bool { + kind := v.Kind() + + for kind == reflect.Interface { + if v.IsNil() { + return true + } + v = v.Elem() + kind = v.Kind() + } + + if z, ok := v.Interface().(isZeroer); ok { + return nilable(kind) && v.IsNil() || z.IsZero() + } + + switch kind { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Ptr: + return v.IsNil() + default: + return false + } +} + +func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, ok bool) { + if len(index) == 1 { + return v.Field(index[0]), true + } + + for i, idx := range index { + if i > 0 { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return v, false + } + v = v.Elem() + } + } + v = v.Field(idx) + } + + return v, true +} + +func fieldByIndexAlloc(v reflect.Value, index []int) reflect.Value { + if len(index) == 1 { + return v.Field(index[0]) + } + + for i, idx := range index { + if i > 0 { + var ok bool + v, ok = indirectNil(v) + if !ok { + return v + } + } + v = v.Field(idx) + } + + return v +} + +func indirectNil(v reflect.Value) (reflect.Value, bool) { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + if !v.CanSet() { + return v, false + } + elemType := v.Type().Elem() + if elemType.Kind() != reflect.Struct { + return v, false + } + v.Set(reflect.New(elemType)) + } + v = v.Elem() + } + return v, true +} diff --git a/vendor/github.com/vmihailenco/msgpack/v5/unsafe.go b/vendor/github.com/vmihailenco/msgpack/v5/unsafe.go new file mode 100644 index 000000000..192ac4792 --- /dev/null +++ b/vendor/github.com/vmihailenco/msgpack/v5/unsafe.go @@ -0,0 +1,22 @@ +// +build !appengine + +package msgpack + +import ( + "unsafe" +) + +// bytesToString converts byte slice to string. +func bytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// stringToBytes converts string to byte slice. +func stringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer( + &struct { + string + Cap int + }{s, len(s)}, + )) +} diff --git a/vendor/github.com/vmihailenco/tagparser/.travis.yml b/vendor/github.com/vmihailenco/tagparser/.travis.yml new file mode 100644 index 000000000..ec5384523 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/.travis.yml @@ -0,0 +1,24 @@ +dist: xenial +sudo: false +language: go + +go: + - 1.11.x + - 1.12.x + - tip + +matrix: + allow_failures: + - go: tip + +env: + - GO111MODULE=on + +go_import_path: github.com/vmihailenco/tagparser + +before_install: + - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1 + +script: + - make + - golangci-lint run diff --git a/vendor/github.com/vmihailenco/tagparser/LICENSE b/vendor/github.com/vmihailenco/tagparser/LICENSE new file mode 100644 index 000000000..3fc93fdff --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2019 The github.com/vmihailenco/tagparser 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. + +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. diff --git a/vendor/github.com/vmihailenco/tagparser/Makefile b/vendor/github.com/vmihailenco/tagparser/Makefile new file mode 100644 index 000000000..fe9dc5bdb --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/Makefile @@ -0,0 +1,8 @@ +all: + go test ./... + go test ./... -short -race + go test ./... -run=NONE -bench=. -benchmem + env GOOS=linux GOARCH=386 go test ./... + go vet ./... + go get github.com/gordonklaus/ineffassign + ineffassign . diff --git a/vendor/github.com/vmihailenco/tagparser/README.md b/vendor/github.com/vmihailenco/tagparser/README.md new file mode 100644 index 000000000..411aa5444 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/README.md @@ -0,0 +1,24 @@ +# Opinionated Golang tag parser + +[![Build Status](https://travis-ci.org/vmihailenco/tagparser.png?branch=master)](https://travis-ci.org/vmihailenco/tagparser) +[![GoDoc](https://godoc.org/github.com/vmihailenco/tagparser?status.svg)](https://godoc.org/github.com/vmihailenco/tagparser) + +## Installation + +Install: + +```shell +go get -u github.com/vmihailenco/tagparser +``` + +## Quickstart + +```go +func ExampleParse() { + tag := tagparser.Parse("some_name,key:value,key2:'complex value'") + fmt.Println(tag.Name) + fmt.Println(tag.Options) + // Output: some_name + // map[key:value key2:'complex value'] +} +``` diff --git a/vendor/github.com/vmihailenco/tagparser/internal/parser/parser.go b/vendor/github.com/vmihailenco/tagparser/internal/parser/parser.go new file mode 100644 index 000000000..2de1c6f7b --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/internal/parser/parser.go @@ -0,0 +1,82 @@ +package parser + +import ( + "bytes" + + "github.com/vmihailenco/tagparser/internal" +) + +type Parser struct { + b []byte + i int +} + +func New(b []byte) *Parser { + return &Parser{ + b: b, + } +} + +func NewString(s string) *Parser { + return New(internal.StringToBytes(s)) +} + +func (p *Parser) Bytes() []byte { + return p.b[p.i:] +} + +func (p *Parser) Valid() bool { + return p.i < len(p.b) +} + +func (p *Parser) Read() byte { + if p.Valid() { + c := p.b[p.i] + p.Advance() + return c + } + return 0 +} + +func (p *Parser) Peek() byte { + if p.Valid() { + return p.b[p.i] + } + return 0 +} + +func (p *Parser) Advance() { + p.i++ +} + +func (p *Parser) Skip(skip byte) bool { + if p.Peek() == skip { + p.Advance() + return true + } + return false +} + +func (p *Parser) SkipBytes(skip []byte) bool { + if len(skip) > len(p.b[p.i:]) { + return false + } + if !bytes.Equal(p.b[p.i:p.i+len(skip)], skip) { + return false + } + p.i += len(skip) + return true +} + +func (p *Parser) ReadSep(sep byte) ([]byte, bool) { + ind := bytes.IndexByte(p.b[p.i:], sep) + if ind == -1 { + b := p.b[p.i:] + p.i = len(p.b) + return b, false + } + + b := p.b[p.i : p.i+ind] + p.i += ind + 1 + return b, true +} diff --git a/vendor/github.com/go-pg/pg/internal/safe.go b/vendor/github.com/vmihailenco/tagparser/internal/safe.go similarity index 100% rename from vendor/github.com/go-pg/pg/internal/safe.go rename to vendor/github.com/vmihailenco/tagparser/internal/safe.go diff --git a/vendor/github.com/go-pg/pg/internal/unsafe.go b/vendor/github.com/vmihailenco/tagparser/internal/unsafe.go similarity index 100% rename from vendor/github.com/go-pg/pg/internal/unsafe.go rename to vendor/github.com/vmihailenco/tagparser/internal/unsafe.go diff --git a/vendor/github.com/go-pg/pg/orm/tag.go b/vendor/github.com/vmihailenco/tagparser/tagparser.go similarity index 66% rename from vendor/github.com/go-pg/pg/orm/tag.go rename to vendor/github.com/vmihailenco/tagparser/tagparser.go index 8d630d646..431002aef 100644 --- a/vendor/github.com/go-pg/pg/orm/tag.go +++ b/vendor/github.com/vmihailenco/tagparser/tagparser.go @@ -1,45 +1,55 @@ -package orm +package tagparser import ( - "github.com/go-pg/pg/internal/parser" + "strings" + + "github.com/vmihailenco/tagparser/internal/parser" ) -type tag struct { +type Tag struct { Name string Options map[string]string } -func parseTag(s string) *tag { +func (t *Tag) HasOption(name string) bool { + _, ok := t.Options[name] + return ok +} + +func Parse(s string) *Tag { p := &tagParser{ Parser: parser.NewString(s), } p.parseKey() - return &p.tag + return &p.Tag } type tagParser struct { *parser.Parser - tag tag + Tag Tag hasName bool key string } func (p *tagParser) setTagOption(key, value string) { + key = strings.TrimSpace(key) + value = strings.TrimSpace(value) + if !p.hasName { p.hasName = true if key == "" { - p.tag.Name = value + p.Tag.Name = value return } } - if p.tag.Options == nil { - p.tag.Options = make(map[string]string) + if p.Tag.Options == nil { + p.Tag.Options = make(map[string]string) } if key == "" { - p.tag.Options[value] = "" + p.Tag.Options[value] = "" } else { - p.tag.Options[key] = value + p.Tag.Options[key] = value } } @@ -87,8 +97,10 @@ func (p *tagParser) parseValue() { c = p.Read() switch c { case '\\': - c = p.Read() + b = append(b, p.Read()) + case '(': b = append(b, c) + b = p.readBrackets(b) case ',': p.Skip(' ') p.setTagOption(p.key, string(b)) @@ -101,6 +113,30 @@ func (p *tagParser) parseValue() { p.setTagOption(p.key, string(b)) } +func (p *tagParser) readBrackets(b []byte) []byte { + var lvl int +loop: + for p.Valid() { + c := p.Read() + switch c { + case '\\': + b = append(b, p.Read()) + case '(': + b = append(b, c) + lvl++ + case ')': + b = append(b, c) + lvl-- + if lvl < 0 { + break loop + } + default: + b = append(b, c) + } + } + return b +} + func (p *tagParser) parseQuotedValue() { const quote = '\'' @@ -132,7 +168,7 @@ func (p *tagParser) parseQuotedValue() { p.parseKey() } -func unquoteTagValue(s string) (string, bool) { +func Unquote(s string) (string, bool) { const quote = '\'' if len(s) < 2 { diff --git a/vendor/github.com/vmihailenco/tagparser/v2/.travis.yml b/vendor/github.com/vmihailenco/tagparser/v2/.travis.yml new file mode 100644 index 000000000..7194cd001 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/.travis.yml @@ -0,0 +1,19 @@ +dist: xenial +language: go + +go: + - 1.14.x + - 1.15.x + - tip + +matrix: + allow_failures: + - go: tip + +env: + - GO111MODULE=on + +go_import_path: github.com/vmihailenco/tagparser + +before_install: + - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1 diff --git a/vendor/github.com/vmihailenco/tagparser/v2/LICENSE b/vendor/github.com/vmihailenco/tagparser/v2/LICENSE new file mode 100644 index 000000000..3fc93fdff --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2019 The github.com/vmihailenco/tagparser 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. + +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. diff --git a/vendor/github.com/vmihailenco/tagparser/v2/Makefile b/vendor/github.com/vmihailenco/tagparser/v2/Makefile new file mode 100644 index 000000000..0b1b59595 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/Makefile @@ -0,0 +1,9 @@ +all: + go test ./... + go test ./... -short -race + go test ./... -run=NONE -bench=. -benchmem + env GOOS=linux GOARCH=386 go test ./... + go vet ./... + go get github.com/gordonklaus/ineffassign + ineffassign . + golangci-lint run diff --git a/vendor/github.com/vmihailenco/tagparser/v2/README.md b/vendor/github.com/vmihailenco/tagparser/v2/README.md new file mode 100644 index 000000000..c0259de56 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/README.md @@ -0,0 +1,24 @@ +# Opinionated Golang tag parser + +[![Build Status](https://travis-ci.org/vmihailenco/tagparser.png?branch=master)](https://travis-ci.org/vmihailenco/tagparser) +[![GoDoc](https://godoc.org/github.com/vmihailenco/tagparser?status.svg)](https://godoc.org/github.com/vmihailenco/tagparser) + +## Installation + +Install: + +```shell +go get github.com/vmihailenco/tagparser/v2 +``` + +## Quickstart + +```go +func ExampleParse() { + tag := tagparser.Parse("some_name,key:value,key2:'complex value'") + fmt.Println(tag.Name) + fmt.Println(tag.Options) + // Output: some_name + // map[key:value key2:'complex value'] +} +``` diff --git a/vendor/github.com/vmihailenco/tagparser/v2/internal/parser/parser.go b/vendor/github.com/vmihailenco/tagparser/v2/internal/parser/parser.go new file mode 100644 index 000000000..21a9bc7f7 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/internal/parser/parser.go @@ -0,0 +1,82 @@ +package parser + +import ( + "bytes" + + "github.com/vmihailenco/tagparser/v2/internal" +) + +type Parser struct { + b []byte + i int +} + +func New(b []byte) *Parser { + return &Parser{ + b: b, + } +} + +func NewString(s string) *Parser { + return New(internal.StringToBytes(s)) +} + +func (p *Parser) Bytes() []byte { + return p.b[p.i:] +} + +func (p *Parser) Valid() bool { + return p.i < len(p.b) +} + +func (p *Parser) Read() byte { + if p.Valid() { + c := p.b[p.i] + p.Advance() + return c + } + return 0 +} + +func (p *Parser) Peek() byte { + if p.Valid() { + return p.b[p.i] + } + return 0 +} + +func (p *Parser) Advance() { + p.i++ +} + +func (p *Parser) Skip(skip byte) bool { + if p.Peek() == skip { + p.Advance() + return true + } + return false +} + +func (p *Parser) SkipBytes(skip []byte) bool { + if len(skip) > len(p.b[p.i:]) { + return false + } + if !bytes.Equal(p.b[p.i:p.i+len(skip)], skip) { + return false + } + p.i += len(skip) + return true +} + +func (p *Parser) ReadSep(sep byte) ([]byte, bool) { + ind := bytes.IndexByte(p.b[p.i:], sep) + if ind == -1 { + b := p.b[p.i:] + p.i = len(p.b) + return b, false + } + + b := p.b[p.i : p.i+ind] + p.i += ind + 1 + return b, true +} diff --git a/vendor/github.com/vmihailenco/tagparser/v2/internal/safe.go b/vendor/github.com/vmihailenco/tagparser/v2/internal/safe.go new file mode 100644 index 000000000..870fe541f --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/internal/safe.go @@ -0,0 +1,11 @@ +// +build appengine + +package internal + +func BytesToString(b []byte) string { + return string(b) +} + +func StringToBytes(s string) []byte { + return []byte(s) +} diff --git a/vendor/github.com/vmihailenco/tagparser/v2/internal/unsafe.go b/vendor/github.com/vmihailenco/tagparser/v2/internal/unsafe.go new file mode 100644 index 000000000..f8bc18d91 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/internal/unsafe.go @@ -0,0 +1,22 @@ +// +build !appengine + +package internal + +import ( + "unsafe" +) + +// BytesToString converts byte slice to string. +func BytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// StringToBytes converts string to byte slice. +func StringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer( + &struct { + string + Cap int + }{s, len(s)}, + )) +} diff --git a/vendor/github.com/vmihailenco/tagparser/v2/tagparser.go b/vendor/github.com/vmihailenco/tagparser/v2/tagparser.go new file mode 100644 index 000000000..5002e6453 --- /dev/null +++ b/vendor/github.com/vmihailenco/tagparser/v2/tagparser.go @@ -0,0 +1,166 @@ +package tagparser + +import ( + "strings" + + "github.com/vmihailenco/tagparser/v2/internal/parser" +) + +type Tag struct { + Name string + Options map[string]string +} + +func (t *Tag) HasOption(name string) bool { + _, ok := t.Options[name] + return ok +} + +func Parse(s string) *Tag { + p := &tagParser{ + Parser: parser.NewString(s), + } + p.parseKey() + return &p.Tag +} + +type tagParser struct { + *parser.Parser + + Tag Tag + hasName bool + key string +} + +func (p *tagParser) setTagOption(key, value string) { + key = strings.TrimSpace(key) + value = strings.TrimSpace(value) + + if !p.hasName { + p.hasName = true + if key == "" { + p.Tag.Name = value + return + } + } + if p.Tag.Options == nil { + p.Tag.Options = make(map[string]string) + } + if key == "" { + p.Tag.Options[value] = "" + } else { + p.Tag.Options[key] = value + } +} + +func (p *tagParser) parseKey() { + p.key = "" + + var b []byte + for p.Valid() { + c := p.Read() + switch c { + case ',': + p.Skip(' ') + p.setTagOption("", string(b)) + p.parseKey() + return + case ':': + p.key = string(b) + p.parseValue() + return + case '\'': + p.parseQuotedValue() + return + default: + b = append(b, c) + } + } + + if len(b) > 0 { + p.setTagOption("", string(b)) + } +} + +func (p *tagParser) parseValue() { + const quote = '\'' + c := p.Peek() + if c == quote { + p.Skip(quote) + p.parseQuotedValue() + return + } + + var b []byte + for p.Valid() { + c = p.Read() + switch c { + case '\\': + b = append(b, p.Read()) + case '(': + b = append(b, c) + b = p.readBrackets(b) + case ',': + p.Skip(' ') + p.setTagOption(p.key, string(b)) + p.parseKey() + return + default: + b = append(b, c) + } + } + p.setTagOption(p.key, string(b)) +} + +func (p *tagParser) readBrackets(b []byte) []byte { + var lvl int +loop: + for p.Valid() { + c := p.Read() + switch c { + case '\\': + b = append(b, p.Read()) + case '(': + b = append(b, c) + lvl++ + case ')': + b = append(b, c) + lvl-- + if lvl < 0 { + break loop + } + default: + b = append(b, c) + } + } + return b +} + +func (p *tagParser) parseQuotedValue() { + const quote = '\'' + var b []byte + for p.Valid() { + bb, ok := p.ReadSep(quote) + if !ok { + b = append(b, bb...) + break + } + + // keep the escaped single-quote, and continue until we've found the + // one that isn't. + if len(bb) > 0 && bb[len(bb)-1] == '\\' { + b = append(b, bb[:len(bb)-1]...) + b = append(b, quote) + continue + } + + b = append(b, bb...) + break + } + + p.setTagOption(p.key, string(b)) + if p.Skip(',') { + p.Skip(' ') + } + p.parseKey() +} diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go new file mode 100644 index 000000000..904b57e01 --- /dev/null +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -0,0 +1,77 @@ +// 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. + +/* +Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC +2898 / PKCS #5 v2.0. + +A key derivation function is useful when encrypting data based on a password +or any other not-fully-random data. It uses a pseudorandom function to derive +a secure encryption key based on the password. + +While v2.0 of the standard defines only one pseudorandom function to use, +HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved +Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To +choose, you can pass the `New` functions from the different SHA packages to +pbkdf2.Key. +*/ +package pbkdf2 // import "golang.org/x/crypto/pbkdf2" + +import ( + "crypto/hmac" + "hash" +) + +// Key derives a key from the password, salt and iteration count, returning a +// []byte of length keylen that can be used as cryptographic key. The key is +// derived based on the method described as PBKDF2 with the HMAC variant using +// the supplied hash function. +// +// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you +// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by +// doing: +// +// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) +// +// Remember to get a good random salt. At least 8 bytes is recommended by the +// RFC. +// +// Using a higher iteration count will increase the cost of an exhaustive +// search but will also make derivation proportionally slower. +func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { + prf := hmac.New(h, password) + hashLen := prf.Size() + numBlocks := (keyLen + hashLen - 1) / hashLen + + var buf [4]byte + dk := make([]byte, 0, numBlocks*hashLen) + U := make([]byte, hashLen) + for block := 1; block <= numBlocks; block++ { + // N.B.: || means concatenation, ^ means XOR + // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter + // U_1 = PRF(password, salt || uint(i)) + prf.Reset() + prf.Write(salt) + buf[0] = byte(block >> 24) + buf[1] = byte(block >> 16) + buf[2] = byte(block >> 8) + buf[3] = byte(block) + prf.Write(buf[:4]) + dk = prf.Sum(dk) + T := dk[len(dk)-hashLen:] + copy(U, T) + + // U_n = PRF(password, U_(n-1)) + for n := 2; n <= iter; n++ { + prf.Reset() + prf.Write(U) + U = U[:0] + U = prf.Sum(U) + for x := range U { + T[x] ^= U[x] + } + } + } + return dk[:keyLen] +} diff --git a/vendor/mellium.im/sasl/.gitignore b/vendor/mellium.im/sasl/.gitignore new file mode 100644 index 000000000..ec356a1a2 --- /dev/null +++ b/vendor/mellium.im/sasl/.gitignore @@ -0,0 +1,6 @@ +*.sw[op] +*.svg +*.xml +*.out +Gopkg.lock +vendor/ diff --git a/vendor/mellium.im/sasl/CHANGELOG.md b/vendor/mellium.im/sasl/CHANGELOG.md new file mode 100644 index 000000000..f5eab4dee --- /dev/null +++ b/vendor/mellium.im/sasl/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +All notable changes to this project will be documented in this file. + + +## v0.3.1 — 2022-12-28 + +### Fixed + +- Sometimes the nonce was not set on the SASL state machine, resulting in + authentication failing + + +## v0.3.0 — 2022-08-15 + +### Added + +- Support for tls-exporter channel binding method as defined in [RFC 9266] +- Support for fast XOR using SIMD/VSX on more architectures + + +### Fixed + +- Return an error if no tls-unique channel binding (CB) data is present in the + TLS connection state (or no connection state exists) and we use SCRAM with CB + + +[RFC 9266]: https://datatracker.ietf.org/doc/html/rfc9266 diff --git a/vendor/mellium.im/sasl/DCO b/vendor/mellium.im/sasl/DCO new file mode 100644 index 000000000..8201f9921 --- /dev/null +++ b/vendor/mellium.im/sasl/DCO @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/vendor/mellium.im/sasl/LICENSE b/vendor/mellium.im/sasl/LICENSE new file mode 100644 index 000000000..08ed8f4db --- /dev/null +++ b/vendor/mellium.im/sasl/LICENSE @@ -0,0 +1,23 @@ +Copyright © 2014 The Mellium Contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +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 HOLDER 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. diff --git a/vendor/mellium.im/sasl/README.md b/vendor/mellium.im/sasl/README.md new file mode 100644 index 000000000..af6983c76 --- /dev/null +++ b/vendor/mellium.im/sasl/README.md @@ -0,0 +1,21 @@ +# SASL + +[![Issue Tracker][badge]](https://mellium.im/issue) +[![Docs](https://pkg.go.dev/badge/mellium.im/sasl)](https://pkg.go.dev/mellium.im/sasl) +[![Chat](https://img.shields.io/badge/XMPP-users@mellium.chat-orange.svg)](https://mellium.chat) +[![License](https://img.shields.io/badge/license-FreeBSD-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) + +
+ +A Go library implementing the Simple Authentication and Security Layer (SASL) as +defined by [RFC 4422][rfc4422]. + + +## License + +The package may be used under the terms of the BSD 2-Clause License a copy of +which may be found in the file [LICENSE.md][LICENSE]. + +[badge]: https://img.shields.io/badge/style-mellium%2fxmpp-green.svg?longCache=true&style=popout-square&label=issues +[rfc4422]: https://tools.ietf.org/html/rfc4422 +[LICENSE]: https://codeberg.org/mellium/xmpp/src/branch/main/LICENSE diff --git a/vendor/mellium.im/sasl/doc.go b/vendor/mellium.im/sasl/doc.go new file mode 100644 index 000000000..a725cb54b --- /dev/null +++ b/vendor/mellium.im/sasl/doc.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +// Package sasl implements the Simple Authentication and Security Layer (SASL) +// as defined by RFC 4422. +// +// Most users of this package will only need to create a Negotiator using +// NewClient or NewServer and call its Step method repeatedly. +// Authors implementing SASL mechanisms other than the builtin ones will want to +// create a Mechanism struct which will likely use the other methods on the +// Negotiator. +// +// Be advised: This API is still unstable and is subject to change. +package sasl // import "mellium.im/sasl" diff --git a/vendor/mellium.im/sasl/mechanism.go b/vendor/mellium.im/sasl/mechanism.go new file mode 100644 index 000000000..d8bbc5a98 --- /dev/null +++ b/vendor/mellium.im/sasl/mechanism.go @@ -0,0 +1,61 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +package sasl + +import ( + /* #nosec */ + "crypto/sha1" + "crypto/sha256" + "errors" +) + +// Define common errors used by SASL mechanisms and negotiators. +var ( + ErrInvalidState = errors.New("invalid state") + ErrInvalidChallenge = errors.New("invalid or missing challenge") + ErrAuthn = errors.New("authentication error") + ErrTooManySteps = errors.New("step called too many times") +) + +var ( + // Plain is a Mechanism that implements the PLAIN authentication mechanism + // as defined by RFC 4616. + Plain Mechanism = plain + + // ScramSha256Plus is a Mechanism that implements the SCRAM-SHA-256-PLUS + // authentication mechanism defined in RFC 7677. + // The only supported channel binding types are tls-unique as defined in RFC + // 5929 and tls-exporter defined in RFC 9266. + ScramSha256Plus Mechanism = scram("SCRAM-SHA-256-PLUS", sha256.New) + + // ScramSha256 is a Mechanism that implements the SCRAM-SHA-256 + // authentication mechanism defined in RFC 7677. + ScramSha256 Mechanism = scram("SCRAM-SHA-256", sha256.New) + + // ScramSha1Plus is a Mechanism that implements the SCRAM-SHA-1-PLUS + // authentication mechanism defined in RFC 5802. + // The only supported channel binding types are tls-unique as defined in RFC + // 5929 and tls-exporter defined in RFC 9266. + ScramSha1Plus Mechanism = scram("SCRAM-SHA-1-PLUS", sha1.New) + + // ScramSha1 is a Mechanism that implements the SCRAM-SHA-1 authentication + // mechanism defined in RFC 5802. + ScramSha1 Mechanism = scram("SCRAM-SHA-1", sha1.New) +) + +// Mechanism represents a SASL mechanism that can be used by a Client or Server +// to perform the actual negotiation. Base64 encoding the final challenges and +// responses should not be performed by the mechanism. +// +// Mechanisms must be stateless and may be shared between goroutines. When a +// mechanism needs to store state between the different steps it can return +// anything that it needs to store and the value will be cached by the +// negotiator and passed in as the data parameter when the next challenge is +// received. +type Mechanism struct { + Name string + Start func(n *Negotiator) (more bool, resp []byte, cache interface{}, err error) + Next func(n *Negotiator, challenge []byte, data interface{}) (more bool, resp []byte, cache interface{}, err error) +} diff --git a/vendor/mellium.im/sasl/negotiator.go b/vendor/mellium.im/sasl/negotiator.go new file mode 100644 index 000000000..8b4c3de09 --- /dev/null +++ b/vendor/mellium.im/sasl/negotiator.go @@ -0,0 +1,196 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +package sasl + +import ( + "crypto/rand" + "crypto/tls" + "strings" +) + +// State represents the current state of a Negotiator. +// The first two bits represent the actual state of the state machine and the +// last 3 bits are a bitmask that define the machines behavior. +// The remaining bits should not be used. +type State uint8 + +// The current step of the Server or Client (represented by the first two bits +// of the state byte). +const ( + Initial State = iota + AuthTextSent + ResponseSent + ValidServerResponse + + // Bitmask used for extracting the step from the state byte. + StepMask = 0x3 +) + +const ( + // RemoteCB bit is on if the remote client or server supports channel binding. + RemoteCB State = 1 << (iota + 3) + + // Errored bit is on if the machine has errored. + Errored + + // Receiving bit is on if the machine is a server. + Receiving +) + +// NewClient creates a new SASL Negotiator that supports creating authentication +// requests using the given mechanism. +func NewClient(m Mechanism, opts ...Option) *Negotiator { + machine := &Negotiator{ + mechanism: m, + } + getOpts(machine, opts...) + for _, rname := range machine.remoteMechanisms { + lname := m.Name + if lname == rname && strings.HasSuffix(lname, "-PLUS") { + machine.state |= RemoteCB + break + } + } + if len(machine.nonce) == 0 { + machine.nonce = nonce(noncerandlen, rand.Reader) + } + return machine +} + +// NewServer creates a new SASL Negotiator that supports receiving +// authentication requests using the given mechanism. +// A nil permissions function is the same as a function that always returns +// false. +func NewServer(m Mechanism, permissions func(*Negotiator) bool, opts ...Option) *Negotiator { + machine := &Negotiator{ + mechanism: m, + state: AuthTextSent | Receiving, + } + getOpts(machine, opts...) + if permissions != nil { + machine.permissions = permissions + } + for _, rname := range machine.remoteMechanisms { + lname := m.Name + if lname == rname && strings.HasSuffix(lname, "-PLUS") { + machine.state |= RemoteCB + break + } + } + if len(machine.nonce) == 0 { + machine.nonce = nonce(noncerandlen, rand.Reader) + } + return machine +} + +// A Negotiator represents a SASL client or server state machine that can +// attempt to negotiate auth. Negotiators should not be used from multiple +// goroutines, and must be reset between negotiation attempts. +type Negotiator struct { + tlsState *tls.ConnectionState + remoteMechanisms []string + credentials func() (Username, Password, Identity []byte) + permissions func(*Negotiator) bool + mechanism Mechanism + state State + nonce []byte + cache interface{} +} + +// Nonce returns a unique nonce that is reset for each negotiation attempt. It +// is used by SASL Mechanisms and should generally not be called directly. +func (c *Negotiator) Nonce() []byte { + return c.nonce +} + +// Step attempts to transition the state machine to its next state. If Step is +// called after a previous invocation generates an error (and the state machine +// has not been reset to its initial state), Step panics. +func (c *Negotiator) Step(challenge []byte) (more bool, resp []byte, err error) { + if c.state&Errored == Errored { + panic("sasl: Step called on a SASL state machine that has errored") + } + defer func() { + if err != nil { + c.state |= Errored + } + }() + + switch c.state & StepMask { + case Initial: + more, resp, c.cache, err = c.mechanism.Start(c) + c.state = c.state&^StepMask | AuthTextSent + case AuthTextSent: + more, resp, c.cache, err = c.mechanism.Next(c, challenge, c.cache) + c.state = c.state&^StepMask | ResponseSent + case ResponseSent: + more, resp, c.cache, err = c.mechanism.Next(c, challenge, c.cache) + c.state = c.state&^StepMask | ValidServerResponse + case ValidServerResponse: + more, resp, c.cache, err = c.mechanism.Next(c, challenge, c.cache) + } + + if err != nil { + return false, nil, err + } + + return more, resp, err +} + +// State returns the internal state of the SASL state machine. +func (c *Negotiator) State() State { + return c.state +} + +// Reset resets the state machine to its initial state so that it can be reused +// in another SASL exchange. +func (c *Negotiator) Reset() { + c.state = c.state & (Receiving | RemoteCB) + + // Skip the start step for servers + if c.state&Receiving == Receiving { + c.state = c.state&^StepMask | AuthTextSent + } + + c.nonce = nonce(noncerandlen, rand.Reader) + c.cache = nil +} + +// Credentials returns a username, and password for authentication and optional +// identity for authorization. +func (c *Negotiator) Credentials() (username, password, identity []byte) { + if c.credentials != nil { + return c.credentials() + } + return +} + +// Permissions is the callback used by the server to authenticate the user. +func (c *Negotiator) Permissions(opts ...Option) bool { + if c.permissions != nil { + nn := *c + getOpts(&nn, opts...) + return c.permissions(&nn) + } + return false +} + +// TLSState is the state of any TLS connections being used to negotiate SASL +// (it can be used for channel binding). +func (c *Negotiator) TLSState() *tls.ConnectionState { + if c.tlsState != nil { + return c.tlsState + } + return nil +} + +// RemoteMechanisms is a list of mechanisms as advertised by the other side of a +// SASL negotiation. +func (c *Negotiator) RemoteMechanisms() []string { + if c.remoteMechanisms != nil { + return c.remoteMechanisms + } + return nil +} diff --git a/vendor/mellium.im/sasl/nonce.go b/vendor/mellium.im/sasl/nonce.go new file mode 100644 index 000000000..e944977b6 --- /dev/null +++ b/vendor/mellium.im/sasl/nonce.go @@ -0,0 +1,30 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +package sasl + +import ( + "encoding/base64" + "io" +) + +// Generates a nonce with n random bytes base64 encoded to ensure that it meets +// the criteria for inclusion in a SCRAM message. +func nonce(n int, r io.Reader) []byte { + if n < 1 { + panic("Cannot generate zero or negative length nonce") + } + b := make([]byte, n) + n2, err := r.Read(b) + switch { + case err != nil: + panic(err) + case n2 != n: + panic("Could not read enough randomness to generate nonce") + } + val := make([]byte, base64.RawStdEncoding.EncodedLen(n)) + base64.RawStdEncoding.Encode(val, b) + + return val +} diff --git a/vendor/mellium.im/sasl/options.go b/vendor/mellium.im/sasl/options.go new file mode 100644 index 000000000..86c295df9 --- /dev/null +++ b/vendor/mellium.im/sasl/options.go @@ -0,0 +1,61 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +package sasl + +import ( + "crypto/tls" +) + +// An Option represents an input to a SASL state machine. +type Option func(*Negotiator) + +func getOpts(n *Negotiator, o ...Option) { + n.credentials = func() (username, password, identity []byte) { + return + } + n.permissions = func(_ *Negotiator) bool { + return false + } + for _, f := range o { + f(n) + } +} + +// TLSState lets the state machine negotiate channel binding with a TLS session +// if supported by the underlying mechanism. +func TLSState(cs tls.ConnectionState) Option { + return func(n *Negotiator) { + n.tlsState = &cs + } +} + +// nonce overrides the nonce used for authentication attempts. +// This defaults to a random value and should not be changed. +func setNonce(v []byte) Option { + return func(n *Negotiator) { + n.nonce = v + } +} + +// RemoteMechanisms sets a list of mechanisms supported by the remote client or +// server with which the state machine will be negotiating. +// It is used to determine if the server supports channel binding. +func RemoteMechanisms(m ...string) Option { + return func(n *Negotiator) { + n.remoteMechanisms = m + } +} + +// Credentials provides the negotiator with a username and password to +// authenticate with and (optionally) an authorization identity. +// Identity will normally be left empty to act as the username. +// The Credentials function is called lazily and may be called multiple times by +// the mechanism. +// It is not memoized by the negotiator. +func Credentials(f func() (Username, Password, Identity []byte)) Option { + return func(n *Negotiator) { + n.credentials = f + } +} diff --git a/vendor/mellium.im/sasl/plain.go b/vendor/mellium.im/sasl/plain.go new file mode 100644 index 000000000..7d3d1a814 --- /dev/null +++ b/vendor/mellium.im/sasl/plain.go @@ -0,0 +1,52 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +package sasl + +import ( + "bytes" +) + +var plainSep = []byte{0} + +var plain = Mechanism{ + Name: "PLAIN", + Start: func(m *Negotiator) (more bool, resp []byte, _ interface{}, err error) { + username, password, identity := m.credentials() + payload := make([]byte, 0, len(identity)+len(username)+len(password)+2) + payload = append(payload, identity...) + payload = append(payload, '\x00') + payload = append(payload, username...) + payload = append(payload, '\x00') + payload = append(payload, password...) + return false, payload, nil, nil + }, + Next: func(m *Negotiator, challenge []byte, _ interface{}) (more bool, resp []byte, _ interface{}, err error) { + // If we're a client, or we're a server that's past the AuthTextSent step, + // we should never actually hit this step. + if m.State()&Receiving != Receiving || m.State()&StepMask != AuthTextSent { + err = ErrTooManySteps + return + } + + // If we're a server, validate that the challenge looks like: + // "Identity\x00Username\x00Password" + parts := bytes.Split(challenge, plainSep) + if len(parts) != 3 { + err = ErrInvalidChallenge + return + } + + if m.Permissions(Credentials(func() (Username, Password, Identity []byte) { + return parts[1], parts[2], parts[0] + })) { + // Everything checks out as far as we know and the server should continue + // to authenticate the user. + return + } + + err = ErrAuthn + return + }, +} diff --git a/vendor/mellium.im/sasl/scram.go b/vendor/mellium.im/sasl/scram.go new file mode 100644 index 000000000..174739707 --- /dev/null +++ b/vendor/mellium.im/sasl/scram.go @@ -0,0 +1,286 @@ +// Copyright 2016 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +package sasl + +import ( + "bytes" + "crypto/hmac" + "crypto/tls" + "encoding/base64" + "errors" + "hash" + "strconv" + "strings" + + "golang.org/x/crypto/pbkdf2" +) + +const ( + exporterLen = 32 + exporterLabel = "EXPORTER-Channel-Binding" + gs2HeaderCBSupportUnique = "p=tls-unique," + gs2HeaderCBSupportExporter = "p=tls-exporter," + gs2HeaderNoServerCBSupport = "y," + gs2HeaderNoCBSupport = "n," +) + +var ( + clientKeyInput = []byte("Client Key") + serverKeyInput = []byte("Server Key") +) + +// The number of random bytes to generate for a nonce. +const noncerandlen = 16 + +func getGS2Header(name string, n *Negotiator) (gs2Header []byte) { + _, _, identity := n.Credentials() + tlsState := n.TLSState() + switch { + case tlsState == nil || !strings.HasSuffix(name, "-PLUS"): + // We do not support channel binding + gs2Header = []byte(gs2HeaderNoCBSupport) + case n.State()&RemoteCB == RemoteCB: + // We support channel binding and the server does too + if tlsState.Version >= tls.VersionTLS13 { + gs2Header = []byte(gs2HeaderCBSupportExporter) + } else { + gs2Header = []byte(gs2HeaderCBSupportUnique) + } + case n.State()&RemoteCB != RemoteCB: + // We support channel binding but the server does not + gs2Header = []byte(gs2HeaderNoServerCBSupport) + } + if len(identity) > 0 { + gs2Header = append(gs2Header, []byte(`a=`)...) + gs2Header = append(gs2Header, identity...) + } + gs2Header = append(gs2Header, ',') + return +} + +func scram(name string, fn func() hash.Hash) Mechanism { + // BUG(ssw): We need a way to cache the SCRAM client and server key + // calculations. + return Mechanism{ + Name: name, + Start: func(m *Negotiator) (bool, []byte, interface{}, error) { + user, _, _ := m.Credentials() + + // Escape "=" and ",". This is mostly the same as bytes.Replace but + // faster because we can do both replacements in a single pass. + n := bytes.Count(user, []byte{'='}) + bytes.Count(user, []byte{','}) + username := make([]byte, len(user)+(n*2)) + w := 0 + start := 0 + for i := 0; i < n; i++ { + j := start + j += bytes.IndexAny(user[start:], "=,") + w += copy(username[w:], user[start:j]) + switch user[j] { + case '=': + w += copy(username[w:], "=3D") + case ',': + w += copy(username[w:], "=2C") + } + start = j + 1 + } + copy(username[w:], user[start:]) + + clientFirstMessage := make([]byte, 5+len(m.Nonce())+len(username)) + copy(clientFirstMessage, "n=") + copy(clientFirstMessage[2:], username) + copy(clientFirstMessage[2+len(username):], ",r=") + copy(clientFirstMessage[5+len(username):], m.Nonce()) + + return true, append(getGS2Header(name, m), clientFirstMessage...), clientFirstMessage, nil + }, + Next: func(m *Negotiator, challenge []byte, data interface{}) (more bool, resp []byte, cache interface{}, err error) { + if len(challenge) == 0 { + return more, resp, cache, ErrInvalidChallenge + } + + if m.State()&Receiving == Receiving { + panic("not yet implemented") + } + return scramClientNext(name, fn, m, challenge, data) + }, + } +} + +func scramClientNext(name string, fn func() hash.Hash, m *Negotiator, challenge []byte, data interface{}) (more bool, resp []byte, cache interface{}, err error) { + _, password, _ := m.Credentials() + state := m.State() + + switch state & StepMask { + case AuthTextSent: + iter := -1 + var salt, nonce []byte + remain := challenge + for { + var field []byte + field, remain = nextParam(remain) + if len(field) < 3 || (len(field) >= 2 && field[1] != '=') { + continue + } + switch field[0] { + case 'i': + ival := string(bytes.TrimRight(field[2:], "\x00")) + + if iter, err = strconv.Atoi(ival); err != nil { + return + } + case 's': + salt = make([]byte, base64.StdEncoding.DecodedLen(len(field)-2)) + var n int + n, err = base64.StdEncoding.Decode(salt, field[2:]) + salt = salt[:n] + if err != nil { + return + } + case 'r': + nonce = field[2:] + case 'm': + // RFC 5802: + // m: This attribute is reserved for future extensibility. In this + // version of SCRAM, its presence in a client or a server message + // MUST cause authentication failure when the attribute is parsed by + // the other end. + err = errors.New("server sent reserved attribute `m'") + return + } + if remain == nil { + break + } + } + + switch { + case iter < 0: + err = errors.New("iteration count is invalid") + return + case nonce == nil || !bytes.HasPrefix(nonce, m.Nonce()): + err = errors.New("server nonce does not match client nonce") + return + case salt == nil: + err = errors.New("server sent empty salt") + return + } + + gs2Header := getGS2Header(name, m) + tlsState := m.TLSState() + var channelBinding []byte + switch plus := strings.HasSuffix(name, "-PLUS"); { + case plus && tlsState == nil: + err = errors.New("sasl: SCRAM with channel binding requires a TLS connection") + return + case bytes.Contains(gs2Header, []byte(gs2HeaderCBSupportExporter)): + keying, err := tlsState.ExportKeyingMaterial(exporterLabel, nil, exporterLen) + if err != nil { + return false, nil, nil, err + } + if len(keying) == 0 { + err = errors.New("sasl: SCRAM with channel binding requires valid TLS keying material") + return false, nil, nil, err + } + channelBinding = make([]byte, 2+base64.StdEncoding.EncodedLen(len(gs2Header)+len(keying))) + channelBinding[0] = 'c' + channelBinding[1] = '=' + base64.StdEncoding.Encode(channelBinding[2:], append(gs2Header, keying...)) + case bytes.Contains(gs2Header, []byte(gs2HeaderCBSupportUnique)): + //lint:ignore SA1019 TLS unique must be supported by SCRAM + if len(tlsState.TLSUnique) == 0 { + err = errors.New("sasl: SCRAM with channel binding requires valid tls-unique data") + return false, nil, nil, err + } + channelBinding = make( + []byte, + //lint:ignore SA1019 TLS unique must be supported by SCRAM + 2+base64.StdEncoding.EncodedLen(len(gs2Header)+len(tlsState.TLSUnique)), + ) + channelBinding[0] = 'c' + channelBinding[1] = '=' + //lint:ignore SA1019 TLS unique must be supported by SCRAM + base64.StdEncoding.Encode(channelBinding[2:], append(gs2Header, tlsState.TLSUnique...)) + default: + channelBinding = make( + []byte, + 2+base64.StdEncoding.EncodedLen(len(gs2Header)), + ) + channelBinding[0] = 'c' + channelBinding[1] = '=' + base64.StdEncoding.Encode(channelBinding[2:], gs2Header) + } + clientFinalMessageWithoutProof := append(channelBinding, []byte(",r=")...) + clientFinalMessageWithoutProof = append(clientFinalMessageWithoutProof, nonce...) + + clientFirstMessage := data.([]byte) + authMessage := append(clientFirstMessage, ',') + authMessage = append(authMessage, challenge...) + authMessage = append(authMessage, ',') + authMessage = append(authMessage, clientFinalMessageWithoutProof...) + + saltedPassword := pbkdf2.Key(password, salt, iter, fn().Size(), fn) + + h := hmac.New(fn, saltedPassword) + _, err = h.Write(serverKeyInput) + if err != nil { + return + } + serverKey := h.Sum(nil) + h.Reset() + + _, err = h.Write(clientKeyInput) + if err != nil { + return + } + clientKey := h.Sum(nil) + + h = hmac.New(fn, serverKey) + _, err = h.Write(authMessage) + if err != nil { + return + } + serverSignature := h.Sum(nil) + + h = fn() + _, err = h.Write(clientKey) + if err != nil { + return + } + storedKey := h.Sum(nil) + h = hmac.New(fn, storedKey) + _, err = h.Write(authMessage) + if err != nil { + return + } + clientSignature := h.Sum(nil) + clientProof := make([]byte, len(clientKey)) + goXORBytes(clientProof, clientKey, clientSignature) + + encodedClientProof := make([]byte, base64.StdEncoding.EncodedLen(len(clientProof))) + base64.StdEncoding.Encode(encodedClientProof, clientProof) + clientFinalMessage := append(clientFinalMessageWithoutProof, []byte(",p=")...) + clientFinalMessage = append(clientFinalMessage, encodedClientProof...) + + return true, clientFinalMessage, serverSignature, nil + case ResponseSent: + clientCalculatedServerFinalMessage := "v=" + base64.StdEncoding.EncodeToString(data.([]byte)) + if clientCalculatedServerFinalMessage != string(challenge) { + err = ErrAuthn + return + } + // Success! + return false, nil, nil, nil + } + err = ErrInvalidState + return +} + +func nextParam(params []byte) ([]byte, []byte) { + idx := bytes.IndexByte(params, ',') + if idx == -1 { + return params, nil + } + return params[:idx], params[idx+1:] +} diff --git a/vendor/mellium.im/sasl/xor.go b/vendor/mellium.im/sasl/xor.go new file mode 100644 index 000000000..90d21a82a --- /dev/null +++ b/vendor/mellium.im/sasl/xor.go @@ -0,0 +1,26 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.20 + +package sasl + +// TODO: remove all the specialized XOR code and use "crypto/subtle".XORBytes +// when Go v1.21 comes out. For more information see: +// https://mellium.im/issue/338 + +func goXORBytes(dst, x, y []byte) int { + n := len(x) + if len(y) < n { + n = len(y) + } + if n == 0 { + return 0 + } + if n > len(dst) { + panic("subtle.XORBytes: dst too short") + } + xorBytes(&dst[0], &x[0], &y[0], n) // arch-specific + return n +} diff --git a/vendor/mellium.im/sasl/xor_amd64.go b/vendor/mellium.im/sasl/xor_amd64.go new file mode 100644 index 000000000..d424bf4de --- /dev/null +++ b/vendor/mellium.im/sasl/xor_amd64.go @@ -0,0 +1,10 @@ +// 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. + +//go:build !purego + +package sasl + +//go:noescape +func xorBytes(dst, a, b *byte, n int) diff --git a/vendor/mellium.im/sasl/xor_amd64.s b/vendor/mellium.im/sasl/xor_amd64.s new file mode 100644 index 000000000..8b04b5870 --- /dev/null +++ b/vendor/mellium.im/sasl/xor_amd64.s @@ -0,0 +1,56 @@ +// 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. + +//go:build !purego + +#include "textflag.h" + +// func xorBytes(dst, a, b *byte, n int) +TEXT ·xorBytes(SB), NOSPLIT, $0 + MOVQ dst+0(FP), BX + MOVQ a+8(FP), SI + MOVQ b+16(FP), CX + MOVQ n+24(FP), DX + TESTQ $15, DX // AND 15 & len, if not zero jump to not_aligned. + JNZ not_aligned + +aligned: + MOVQ $0, AX // position in slices + +loop16b: + MOVOU (SI)(AX*1), X0 // XOR 16byte forwards. + MOVOU (CX)(AX*1), X1 + PXOR X1, X0 + MOVOU X0, (BX)(AX*1) + ADDQ $16, AX + CMPQ DX, AX + JNE loop16b + RET + +loop_1b: + SUBQ $1, DX // XOR 1byte backwards. + MOVB (SI)(DX*1), DI + MOVB (CX)(DX*1), AX + XORB AX, DI + MOVB DI, (BX)(DX*1) + TESTQ $7, DX // AND 7 & len, if not zero jump to loop_1b. + JNZ loop_1b + CMPQ DX, $0 // if len is 0, ret. + JE ret + TESTQ $15, DX // AND 15 & len, if zero jump to aligned. + JZ aligned + +not_aligned: + TESTQ $7, DX // AND $7 & len, if not zero jump to loop_1b. + JNE loop_1b + SUBQ $8, DX // XOR 8bytes backwards. + MOVQ (SI)(DX*1), DI + MOVQ (CX)(DX*1), AX + XORQ AX, DI + MOVQ DI, (BX)(DX*1) + CMPQ DX, $16 // if len is greater or equal 16 here, it must be aligned. + JGE aligned + +ret: + RET diff --git a/vendor/mellium.im/sasl/xor_arm64.go b/vendor/mellium.im/sasl/xor_arm64.go new file mode 100644 index 000000000..08525c6db --- /dev/null +++ b/vendor/mellium.im/sasl/xor_arm64.go @@ -0,0 +1,10 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +package sasl + +//go:noescape +func xorBytes(dst, a, b *byte, n int) diff --git a/vendor/mellium.im/sasl/xor_arm64.s b/vendor/mellium.im/sasl/xor_arm64.s new file mode 100644 index 000000000..76321645d --- /dev/null +++ b/vendor/mellium.im/sasl/xor_arm64.s @@ -0,0 +1,69 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +#include "textflag.h" + +// func xorBytes(dst, a, b *byte, n int) +TEXT ·xorBytes(SB), NOSPLIT|NOFRAME, $0 + MOVD dst+0(FP), R0 + MOVD a+8(FP), R1 + MOVD b+16(FP), R2 + MOVD n+24(FP), R3 + CMP $64, R3 + BLT tail +loop_64: + VLD1.P 64(R1), [V0.B16, V1.B16, V2.B16, V3.B16] + VLD1.P 64(R2), [V4.B16, V5.B16, V6.B16, V7.B16] + VEOR V0.B16, V4.B16, V4.B16 + VEOR V1.B16, V5.B16, V5.B16 + VEOR V2.B16, V6.B16, V6.B16 + VEOR V3.B16, V7.B16, V7.B16 + VST1.P [V4.B16, V5.B16, V6.B16, V7.B16], 64(R0) + SUBS $64, R3 + CMP $64, R3 + BGE loop_64 +tail: + // quick end + CBZ R3, end + TBZ $5, R3, less_than32 + VLD1.P 32(R1), [V0.B16, V1.B16] + VLD1.P 32(R2), [V2.B16, V3.B16] + VEOR V0.B16, V2.B16, V2.B16 + VEOR V1.B16, V3.B16, V3.B16 + VST1.P [V2.B16, V3.B16], 32(R0) +less_than32: + TBZ $4, R3, less_than16 + LDP.P 16(R1), (R11, R12) + LDP.P 16(R2), (R13, R14) + EOR R11, R13, R13 + EOR R12, R14, R14 + STP.P (R13, R14), 16(R0) +less_than16: + TBZ $3, R3, less_than8 + MOVD.P 8(R1), R11 + MOVD.P 8(R2), R12 + EOR R11, R12, R12 + MOVD.P R12, 8(R0) +less_than8: + TBZ $2, R3, less_than4 + MOVWU.P 4(R1), R13 + MOVWU.P 4(R2), R14 + EORW R13, R14, R14 + MOVWU.P R14, 4(R0) +less_than4: + TBZ $1, R3, less_than2 + MOVHU.P 2(R1), R15 + MOVHU.P 2(R2), R16 + EORW R15, R16, R16 + MOVHU.P R16, 2(R0) +less_than2: + TBZ $0, R3, end + MOVBU (R1), R17 + MOVBU (R2), R19 + EORW R17, R19, R19 + MOVBU R19, (R0) +end: + RET diff --git a/vendor/mellium.im/sasl/xor_generic.go b/vendor/mellium.im/sasl/xor_generic.go new file mode 100644 index 000000000..1b49158e5 --- /dev/null +++ b/vendor/mellium.im/sasl/xor_generic.go @@ -0,0 +1,58 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!amd64 && !arm64 && !ppc64 && !ppc64le) || purego + +package sasl + +import ( + "runtime" + "unsafe" +) + +const wordSize = unsafe.Sizeof(uintptr(0)) + +const supportsUnaligned = runtime.GOARCH == "386" || + runtime.GOARCH == "amd64" || + runtime.GOARCH == "ppc64" || + runtime.GOARCH == "ppc64le" || + runtime.GOARCH == "s390x" + +func xorBytes(dstb, xb, yb *byte, n int) { + // xorBytes assembly is written using pointers and n. Back to slices. + dst := unsafe.Slice(dstb, n) + x := unsafe.Slice(xb, n) + y := unsafe.Slice(yb, n) + + if supportsUnaligned || aligned(dstb, xb, yb) { + xorLoop(words(dst), words(x), words(y)) + if uintptr(n)%wordSize == 0 { + return + } + done := n &^ int(wordSize-1) + dst = dst[done:] + x = x[done:] + y = y[done:] + } + xorLoop(dst, x, y) +} + +// aligned reports whether dst, x, and y are all word-aligned pointers. +func aligned(dst, x, y *byte) bool { + return (uintptr(unsafe.Pointer(dst))|uintptr(unsafe.Pointer(x))|uintptr(unsafe.Pointer(y)))&(wordSize-1) == 0 +} + +// words returns a []uintptr pointing at the same data as x, +// with any trailing partial word removed. +func words(x []byte) []uintptr { + return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), uintptr(len(x))/wordSize) +} + +func xorLoop[T byte | uintptr](dst, x, y []T) { + x = x[:len(dst)] // remove bounds check in loop + y = y[:len(dst)] // remove bounds check in loop + for i := range dst { + dst[i] = x[i] ^ y[i] + } +} diff --git a/vendor/mellium.im/sasl/xor_go.go b/vendor/mellium.im/sasl/xor_go.go new file mode 100644 index 000000000..3d742f507 --- /dev/null +++ b/vendor/mellium.im/sasl/xor_go.go @@ -0,0 +1,15 @@ +// Copyright 2022 The Mellium Contributors. +// Use of this source code is governed by the BSD 2-clause +// license that can be found in the LICENSE file. + +//go:build go1.20 + +package sasl + +import ( + "crypto/subtle" +) + +func goXORBytes(dst, x, y []byte) int { + return subtle.XORBytes(dst, x, y) +} diff --git a/vendor/mellium.im/sasl/xor_ppc64x.go b/vendor/mellium.im/sasl/xor_ppc64x.go new file mode 100644 index 000000000..0148b3009 --- /dev/null +++ b/vendor/mellium.im/sasl/xor_ppc64x.go @@ -0,0 +1,10 @@ +// 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. + +//go:build (ppc64 || ppc64le) && !purego + +package sasl + +//go:noescape +func xorBytes(dst, a, b *byte, n int) diff --git a/vendor/mellium.im/sasl/xor_ppc64x.s b/vendor/mellium.im/sasl/xor_ppc64x.s new file mode 100644 index 000000000..72bb80d24 --- /dev/null +++ b/vendor/mellium.im/sasl/xor_ppc64x.s @@ -0,0 +1,87 @@ +// 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. + +//go:build (ppc64 || ppc64le) && !purego + +#include "textflag.h" + +// func xorBytes(dst, a, b *byte, n int) +TEXT ·xorBytes(SB), NOSPLIT, $0 + MOVD dst+0(FP), R3 // R3 = dst + MOVD a+8(FP), R4 // R4 = a + MOVD b+16(FP), R5 // R5 = b + MOVD n+24(FP), R6 // R6 = n + + CMPU R6, $32, CR7 // Check if n ≥ 32 bytes + MOVD R0, R8 // R8 = index + CMPU R6, $8, CR6 // Check if 8 ≤ n < 32 bytes + BLT CR6, small // Smaller than 8 + BLT CR7, xor16 // Case for 16 ≤ n < 32 bytes + + // Case for n ≥ 32 bytes +preloop32: + SRD $5, R6, R7 // Setup loop counter + MOVD R7, CTR + MOVD $16, R10 + ANDCC $31, R6, R9 // Check for tailing bytes for later +loop32: + LXVD2X (R4)(R8), VS32 // VS32 = a[i,...,i+15] + LXVD2X (R4)(R10), VS34 + LXVD2X (R5)(R8), VS33 // VS33 = b[i,...,i+15] + LXVD2X (R5)(R10), VS35 + XXLXOR VS32, VS33, VS32 // VS34 = a[] ^ b[] + XXLXOR VS34, VS35, VS34 + STXVD2X VS32, (R3)(R8) // Store to dst + STXVD2X VS34, (R3)(R10) + ADD $32, R8 // Update index + ADD $32, R10 + BC 16, 0, loop32 // bdnz loop16 + + BEQ CR0, done + + MOVD R9, R6 + CMP R6, $8 + BLT small +xor16: + CMP R6, $16 + BLT xor8 + LXVD2X (R4)(R8), VS32 + LXVD2X (R5)(R8), VS33 + XXLXOR VS32, VS33, VS32 + STXVD2X VS32, (R3)(R8) + ADD $16, R8 + ADD $-16, R6 + CMP R6, $8 + BLT small +xor8: + // Case for 8 ≤ n < 16 bytes + MOVD (R4)(R8), R14 // R14 = a[i,...,i+7] + MOVD (R5)(R8), R15 // R15 = b[i,...,i+7] + XOR R14, R15, R16 // R16 = a[] ^ b[] + SUB $8, R6 // n = n - 8 + MOVD R16, (R3)(R8) // Store to dst + ADD $8, R8 + + // Check if we're finished + CMP R6, R0 + BGT small + RET + + // Case for n < 8 bytes and tailing bytes from the + // previous cases. +small: + CMP R6, R0 + BEQ done + MOVD R6, CTR // Setup loop counter + +loop: + MOVBZ (R4)(R8), R14 // R14 = a[i] + MOVBZ (R5)(R8), R15 // R15 = b[i] + XOR R14, R15, R16 // R16 = a[i] ^ b[i] + MOVB R16, (R3)(R8) // Store to dst + ADD $1, R8 + BC 16, 0, loop // bdnz loop + +done: + RET diff --git a/vendor/modules.txt b/vendor/modules.txt index c4dd94621..069567c3b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -162,14 +162,18 @@ github.com/go-kivik/couchdb/v3/chttp github.com/go-kivik/kivik/v3 github.com/go-kivik/kivik/v3/driver github.com/go-kivik/kivik/v3/internal/registry -# github.com/go-pg/pg v6.14.5+incompatible -## explicit -github.com/go-pg/pg -github.com/go-pg/pg/internal -github.com/go-pg/pg/internal/parser -github.com/go-pg/pg/internal/pool -github.com/go-pg/pg/orm -github.com/go-pg/pg/types +# github.com/go-pg/pg/v10 v10.12.0 +## explicit; go 1.19 +github.com/go-pg/pg/v10 +github.com/go-pg/pg/v10/internal +github.com/go-pg/pg/v10/internal/parser +github.com/go-pg/pg/v10/internal/pool +github.com/go-pg/pg/v10/orm +github.com/go-pg/pg/v10/pgjson +github.com/go-pg/pg/v10/types +# github.com/go-pg/zerochecker v0.2.0 +## explicit; go 1.13 +github.com/go-pg/zerochecker # github.com/go-redis/redis/v7 v7.4.1 ## explicit; go 1.11 github.com/go-redis/redis/v7 @@ -365,7 +369,7 @@ github.com/jgautheron/goconst # github.com/jingyugao/rowserrcheck v1.1.1 ## explicit; go 1.13 github.com/jingyugao/rowserrcheck/passes/rowserr -# github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a +# github.com/jinzhu/inflection v1.0.0 ## explicit github.com/jinzhu/inflection # github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af @@ -717,6 +721,9 @@ github.com/timonwong/loggercheck/internal/checkers/printf github.com/timonwong/loggercheck/internal/rules github.com/timonwong/loggercheck/internal/sets github.com/timonwong/loggercheck/internal/stringutil +# github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc +## explicit +github.com/tmthrgd/go-hex # github.com/tomarrell/wrapcheck/v2 v2.8.0 ## explicit; go 1.18 github.com/tomarrell/wrapcheck/v2/wrapcheck @@ -758,6 +765,23 @@ github.com/ultraware/whitespace # github.com/uudashr/gocognit v1.0.6 ## explicit; go 1.16 github.com/uudashr/gocognit +# github.com/vmihailenco/bufpool v0.1.11 +## explicit; go 1.13 +github.com/vmihailenco/bufpool +# github.com/vmihailenco/msgpack/v5 v5.3.4 +## explicit; go 1.11 +github.com/vmihailenco/msgpack/v5 +github.com/vmihailenco/msgpack/v5/msgpcode +# github.com/vmihailenco/tagparser v0.1.2 +## explicit; go 1.13 +github.com/vmihailenco/tagparser +github.com/vmihailenco/tagparser/internal +github.com/vmihailenco/tagparser/internal/parser +# github.com/vmihailenco/tagparser/v2 v2.0.0 +## explicit; go 1.15 +github.com/vmihailenco/tagparser/v2 +github.com/vmihailenco/tagparser/v2/internal +github.com/vmihailenco/tagparser/v2/internal/parser # github.com/yagipy/maintidx v1.0.0 ## explicit; go 1.17 github.com/yagipy/maintidx @@ -790,6 +814,7 @@ go.uber.org/zap/zapcore ## explicit; go 1.18 golang.org/x/crypto/argon2 golang.org/x/crypto/blake2b +golang.org/x/crypto/pbkdf2 # golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e ## explicit; go 1.18 golang.org/x/exp/constraints @@ -1077,6 +1102,9 @@ honnef.co/go/tools/staticcheck/fakereflect honnef.co/go/tools/staticcheck/fakexml honnef.co/go/tools/stylecheck honnef.co/go/tools/unused +# mellium.im/sasl v0.3.1 +## explicit; go 1.18 +mellium.im/sasl # mvdan.cc/gofumpt v0.4.0 ## explicit; go 1.18 mvdan.cc/gofumpt/format From 45ded84a989bc5f7c31a9a7feef324782f5bb155 Mon Sep 17 00:00:00 2001 From: Thomas Hipp Date: Tue, 9 Apr 2024 22:59:36 +0200 Subject: [PATCH 31/31] Update to go-pg/v10 --- backend/postgres/errors.go | 2 +- backend/postgres/errors_test.go | 2 +- backend/postgres/health_postgres.go | 2 +- backend/postgres/health_postgres_test.go | 2 +- backend/postgres/hooks.go | 136 +++++++++++++++++++ backend/postgres/metrics.go | 2 +- backend/postgres/postgres.go | 119 +--------------- backend/postgres/query_ctx.go | 4 +- http/jsonapi/runtime/standard_params.go | 4 +- http/jsonapi/runtime/standard_params_test.go | 26 ++-- 10 files changed, 164 insertions(+), 135 deletions(-) create mode 100644 backend/postgres/hooks.go diff --git a/backend/postgres/errors.go b/backend/postgres/errors.go index 322dbdb41..ca910c04d 100644 --- a/backend/postgres/errors.go +++ b/backend/postgres/errors.go @@ -8,7 +8,7 @@ import ( "io" "net" - "github.com/go-pg/pg" + "github.com/go-pg/pg/v10" ) var ( diff --git a/backend/postgres/errors_test.go b/backend/postgres/errors_test.go index 9df6cce7c..d5bd38ac8 100644 --- a/backend/postgres/errors_test.go +++ b/backend/postgres/errors_test.go @@ -6,7 +6,7 @@ import ( "io" "testing" - "github.com/go-pg/pg" + "github.com/go-pg/pg/v10" "github.com/stretchr/testify/require" pbpostgres "github.com/pace/bricks/backend/postgres" diff --git a/backend/postgres/health_postgres.go b/backend/postgres/health_postgres.go index 2acf78bc2..ccdbb6497 100644 --- a/backend/postgres/health_postgres.go +++ b/backend/postgres/health_postgres.go @@ -7,7 +7,7 @@ import ( "context" "time" - "github.com/go-pg/pg/orm" + "github.com/go-pg/pg/v10/orm" "github.com/pace/bricks/maintenance/health/servicehealthcheck" ) diff --git a/backend/postgres/health_postgres_test.go b/backend/postgres/health_postgres_test.go index 829bbd1cf..3ada9c556 100644 --- a/backend/postgres/health_postgres_test.go +++ b/backend/postgres/health_postgres_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/go-pg/pg/orm" + "github.com/go-pg/pg/v10/orm" http2 "github.com/pace/bricks/http" "github.com/pace/bricks/maintenance/errors" "github.com/pace/bricks/maintenance/health/servicehealthcheck" diff --git a/backend/postgres/hooks.go b/backend/postgres/hooks.go new file mode 100644 index 000000000..98e527bf6 --- /dev/null +++ b/backend/postgres/hooks.go @@ -0,0 +1,136 @@ +package postgres + +import ( + "context" + "math" + "time" + + "github.com/go-pg/pg/v10" + "github.com/opentracing/opentracing-go" + olog "github.com/opentracing/opentracing-go/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/rs/zerolog" + + "github.com/pace/bricks/maintenance/log" +) + +type QueryLogger struct{} + +func (QueryLogger) BeforeQuery(_ context.Context, _ *pg.QueryEvent) (context.Context, error) { + return nil, nil +} + +func (QueryLogger) AfterQuery(ctx context.Context, event *pg.QueryEvent) error { + q, qe := event.UnformattedQuery() + if qe == nil { + if !(cfg.LogRead || cfg.LogWrite) { + return nil + } + // we can only and should only perfom the following check if we have the information availaible + mode := determineQueryMode(string(q)) + if mode == readMode && !cfg.LogRead { + return nil + } + if mode == writeMode && !cfg.LogWrite { + return nil + } + + } + + dur := float64(time.Since(event.StartTime)) / float64(time.Millisecond) + + // check if log context is given + var logger *zerolog.Logger + if ctx != nil { + logger = log.Ctx(ctx) + } else { + logger = log.Logger() + } + + // add general info + le := logger.Debug(). + Float64("duration", dur). + Str("sentry:category", "postgres") + + // add error or result set info + if event.Err != nil { + le = le.Err(event.Err) + } else { + le = le.Int("affected", event.Result.RowsAffected()). + Int("rows", event.Result.RowsReturned()) + } + + if qe != nil { + // this is only a display issue not a "real" issue + le.Msgf("%v", qe) + } + le.Msg(string(q)) + + return nil +} + +type OpenTracingAdapter struct{} + +func (OpenTracingAdapter) BeforeQuery(_ context.Context, _ *pg.QueryEvent) (context.Context, error) { + return nil, nil +} + +func (OpenTracingAdapter) AfterQuery(ctx context.Context, event *pg.QueryEvent) error { + // start span with general info + q, qe := event.UnformattedQuery() + if qe != nil { + // this is only a display issue not a "real" issue + q = []byte(qe.Error()) + } + + span, _ := opentracing.StartSpanFromContext(event.DB.Context(), "sql: "+getQueryType(string(q)), + opentracing.StartTime(event.StartTime)) + + span.SetTag("db.system", "postgres") + + fields := []olog.Field{ + olog.String("query", string(q)), + } + + // add error or result set info + if event.Err != nil { + fields = append(fields, olog.Error(event.Err)) + } else { + fields = append(fields, + olog.Int("affected", event.Result.RowsAffected()), + olog.Int("rows", event.Result.RowsReturned())) + } + + span.LogFields(fields...) + span.Finish() + + return nil +} + +type MetricsAdapter struct { + opts *pg.Options +} + +func (MetricsAdapter) BeforeQuery(_ context.Context, _ *pg.QueryEvent) (context.Context, error) { + return nil, nil +} + +func (m MetricsAdapter) AfterQuery(ctx context.Context, event *pg.QueryEvent) error { + dur := float64(time.Since(event.StartTime)) / float64(time.Millisecond) + labels := prometheus.Labels{ + "database": m.opts.Addr + "/" + m.opts.Database, + } + + metricQueryTotal.With(labels).Inc() + + if event.Err != nil { + metricQueryFailed.With(labels).Inc() + } else { + r := event.Result + metricQueryRowsTotal.With(labels).Add(float64(r.RowsReturned())) + metricQueryAffectedTotal.With(labels).Add(math.Max(0, float64(r.RowsAffected()))) + } + metricQueryDurationSeconds.With(labels).Observe(dur) + + return nil +} diff --git a/backend/postgres/metrics.go b/backend/postgres/metrics.go index 1fa9e0201..553b95f96 100644 --- a/backend/postgres/metrics.go +++ b/backend/postgres/metrics.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/go-pg/pg" + "github.com/go-pg/pg/v10" "github.com/prometheus/client_golang/prometheus" ) diff --git a/backend/postgres/postgres.go b/backend/postgres/postgres.go index ef6bb4749..d8956df89 100644 --- a/backend/postgres/postgres.go +++ b/backend/postgres/postgres.go @@ -7,7 +7,6 @@ package postgres import ( "context" "fmt" - "math" "os" "path/filepath" "regexp" @@ -16,11 +15,8 @@ import ( "time" "github.com/caarlos0/env/v10" - "github.com/go-pg/pg" - "github.com/opentracing/opentracing-go" - olog "github.com/opentracing/opentracing-go/log" + "github.com/go-pg/pg/v10" "github.com/prometheus/client_golang/prometheus" - "github.com/rs/zerolog" "github.com/pace/bricks/maintenance/health/servicehealthcheck" "github.com/pace/bricks/maintenance/log" @@ -234,14 +230,14 @@ func CustomConnectionPool(opts *pg.Options) *pg.DB { Msg("PostgreSQL connection pool created") db := pg.Connect(opts) if cfg.LogWrite || cfg.LogRead { - db.OnQueryProcessed(queryLogger) + db.AddQueryHook(QueryLogger{}) } else { log.Logger().Warn().Msg("Connection pool has logging queries disabled completely") } - db.OnQueryProcessed(openTracingAdapter) - db.OnQueryProcessed(func(event *pg.QueryProcessedEvent) { - metricsAdapter(event, opts) - }) + + db.AddQueryHook(OpenTracingAdapter{}) + db.AddQueryHook(MetricsAdapter{opts}) + return db } @@ -261,57 +257,6 @@ func determineQueryMode(qry string) queryMode { return writeMode } -func queryLogger(event *pg.QueryProcessedEvent) { - q, qe := event.UnformattedQuery() - if qe == nil { - if !(cfg.LogRead || cfg.LogWrite) { - return - } - // we can only and should only perfom the following check if we have the information availaible - mode := determineQueryMode(q) - if mode == readMode && !cfg.LogRead { - return - } - if mode == writeMode && !cfg.LogWrite { - return - } - - } - ctx := event.DB.Context() - dur := float64(time.Since(event.StartTime)) / float64(time.Millisecond) - - // check if log context is given - var logger *zerolog.Logger - if ctx != nil { - logger = log.Ctx(ctx) - } else { - logger = log.Logger() - } - - // add general info - le := logger.Debug(). - Str("file", event.File). - Int("line", event.Line). - Str("func", event.Func). - Int("attempt", event.Attempt). - Float64("duration", dur). - Str("sentry:category", "postgres") - - // add error or result set info - if event.Error != nil { - le = le.Err(event.Error) - } else { - le = le.Int("affected", event.Result.RowsAffected()). - Int("rows", event.Result.RowsReturned()) - } - - if qe != nil { - // this is only a display issue not a "real" issue - le.Msgf("%v", qe) - } - le.Msg(q) -} - var reQueryType = regexp.MustCompile(`(\s)`) var reQueryTypeCleanup = regexp.MustCompile(`(?m)(\s+|\n)`) @@ -325,55 +270,3 @@ func getQueryType(s string) string { } return strings.ToUpper(s) } - -func openTracingAdapter(event *pg.QueryProcessedEvent) { - // start span with general info - q, qe := event.UnformattedQuery() - if qe != nil { - // this is only a display issue not a "real" issue - q = qe.Error() - } - - span, _ := opentracing.StartSpanFromContext(event.DB.Context(), "sql: "+getQueryType(q), - opentracing.StartTime(event.StartTime)) - - span.SetTag("db.system", "postgres") - - fields := []olog.Field{ - olog.String("file", event.File), - olog.Int("line", event.Line), - olog.String("func", event.Func), - olog.Int("attempt", event.Attempt), - olog.String("query", q), - } - - // add error or result set info - if event.Error != nil { - fields = append(fields, olog.Error(event.Error)) - } else { - fields = append(fields, - olog.Int("affected", event.Result.RowsAffected()), - olog.Int("rows", event.Result.RowsReturned())) - } - - span.LogFields(fields...) - span.Finish() -} - -func metricsAdapter(event *pg.QueryProcessedEvent, opts *pg.Options) { - dur := float64(time.Since(event.StartTime)) / float64(time.Millisecond) - labels := prometheus.Labels{ - "database": opts.Addr + "/" + opts.Database, - } - - metricQueryTotal.With(labels).Inc() - - if event.Error != nil { - metricQueryFailed.With(labels).Inc() - } else { - r := event.Result - metricQueryRowsTotal.With(labels).Add(float64(r.RowsReturned())) - metricQueryAffectedTotal.With(labels).Add(math.Max(0, float64(r.RowsAffected()))) - } - metricQueryDurationSeconds.With(labels).Observe(dur) -} diff --git a/backend/postgres/query_ctx.go b/backend/postgres/query_ctx.go index 9325edd65..d3842d87c 100644 --- a/backend/postgres/query_ctx.go +++ b/backend/postgres/query_ctx.go @@ -6,8 +6,8 @@ package postgres import ( "context" - "github.com/go-pg/pg" - "github.com/go-pg/pg/orm" + "github.com/go-pg/pg/v10" + "github.com/go-pg/pg/v10/orm" ) type pgPoolAdapter struct { diff --git a/http/jsonapi/runtime/standard_params.go b/http/jsonapi/runtime/standard_params.go index d4c0c4baa..61aab9ae6 100644 --- a/http/jsonapi/runtime/standard_params.go +++ b/http/jsonapi/runtime/standard_params.go @@ -10,8 +10,8 @@ import ( "strings" "github.com/caarlos0/env/v10" - "github.com/go-pg/pg" - "github.com/go-pg/pg/orm" + "github.com/go-pg/pg/v10" + "github.com/go-pg/pg/v10/orm" "github.com/pace/bricks/maintenance/log" ) diff --git a/http/jsonapi/runtime/standard_params_test.go b/http/jsonapi/runtime/standard_params_test.go index 84c0d798b..0a83a8191 100644 --- a/http/jsonapi/runtime/standard_params_test.go +++ b/http/jsonapi/runtime/standard_params_test.go @@ -9,8 +9,8 @@ import ( "sort" "testing" - "github.com/go-pg/pg" - "github.com/go-pg/pg/orm" + "github.com/go-pg/pg/v10" + "github.com/go-pg/pg/v10/orm" "github.com/stretchr/testify/assert" "github.com/pace/bricks/backend/postgres" @@ -38,7 +38,7 @@ func TestIntegrationFilterParameter(t *testing.T) { db := setupDatabase(a) defer func() { // Tear Down - err := db.DropTable(&TestModel{}, &orm.DropTableOptions{}) + err := db.Model(&TestModel{}).DropTable(&orm.DropTableOptions{}) assert.NoError(t, err) }() @@ -118,40 +118,40 @@ func TestIntegrationFilterParameter(t *testing.T) { } func setupDatabase(a *assert.Assertions) *pg.DB { - dB := postgres.DefaultConnectionPool() - dB = dB.WithContext(log.WithContext(context.Background())) + db := postgres.DefaultConnectionPool() + db = db.WithContext(log.WithContext(context.Background())) - err := dB.CreateTable(&TestModel{}, &orm.CreateTableOptions{}) + err := db.Model(&TestModel{}).CreateTable(&orm.CreateTableOptions{}) a.NoError(err) - _, err = dB.Model(&TestModel{ + _, err = db.Model(&TestModel{ FilterName: "a", }).Insert() a.NoError(err) - _, err = dB.Model(&TestModel{ + _, err = db.Model(&TestModel{ FilterName: "b", }).Insert() a.NoError(err) - _, err = dB.Model(&TestModel{ + _, err = db.Model(&TestModel{ FilterName: "c", }).Insert() a.NoError(err) - _, err = dB.Model(&TestModel{ + _, err = db.Model(&TestModel{ FilterName: "d", }).Insert() a.NoError(err) - _, err = dB.Model(&TestModel{ + _, err = db.Model(&TestModel{ FilterName: "e", }).Insert() a.NoError(err) - _, err = dB.Model(&TestModel{ + _, err = db.Model(&TestModel{ FilterName: "f", }).Insert() a.NoError(err) - return dB + return db }