From 023c10e0a4b21c1f80d611318a9d0ea0fb6a8db7 Mon Sep 17 00:00:00 2001 From: Uman Shahzad Date: Mon, 18 Dec 2023 13:04:34 +0500 Subject: [PATCH] update deps --- go.mod | 24 +- go.sum | 24 + vendor/github.com/fatih/color/README.md | 14 +- vendor/github.com/fatih/color/color.go | 98 +- .../github.com/fatih/color/color_windows.go | 19 + vendor/github.com/fatih/color/doc.go | 137 +- .../ipinfo/mmdbctl/lib/cmd_import.go | 11 +- .../github.com/ipinfo/mmdbctl/lib/cmd_read.go | 4 +- .../github.com/mattn/go-colorable/.travis.yml | 15 - .../github.com/mattn/go-colorable/README.md | 2 +- .../mattn/go-colorable/colorable_appengine.go | 1 + .../mattn/go-colorable/colorable_others.go | 4 +- .../mattn/go-colorable/colorable_windows.go | 14 +- .../mattn/go-colorable/noncolorable.go | 15 +- .../github.com/mattn/go-isatty/isatty_bsd.go | 5 +- .../mattn/go-isatty/isatty_others.go | 5 +- .../mattn/go-isatty/isatty_tcgets.go | 3 +- .../maxmind/mmdbwriter/.golangci.toml | 1031 +++++---- .../github.com/maxmind/mmdbwriter/data_key.go | 25 +- .../github.com/maxmind/mmdbwriter/data_map.go | 13 +- .../maxmind/mmdbwriter/data_section.go | 2 +- .../github.com/maxmind/mmdbwriter/errors.go | 124 ++ .../maxmind/mmdbwriter/mmdbtype/types.go | 173 +- vendor/github.com/maxmind/mmdbwriter/node.go | 110 +- vendor/github.com/maxmind/mmdbwriter/tree.go | 45 +- .../oschwald/maxminddb-golang/.golangci.toml | 136 +- .../oschwald/maxminddb-golang/decoder.go | 28 +- .../oschwald/maxminddb-golang/errors.go | 8 +- .../oschwald/maxminddb-golang/mmap_unix.go | 4 +- .../oschwald/maxminddb-golang/mmap_windows.go | 1 + .../oschwald/maxminddb-golang/reader.go | 22 +- .../maxminddb-golang/reader_appengine.go | 28 - .../maxminddb-golang/reader_memory.go | 26 + .../{reader_other.go => reader_mmap.go} | 16 +- .../oschwald/maxminddb-golang/set_zero_120.go | 10 + .../maxminddb-golang/set_zero_pre120.go | 10 + .../oschwald/maxminddb-golang/traverse.go | 11 +- .../oschwald/maxminddb-golang/verifier.go | 6 +- vendor/github.com/posener/script/cat.go | 16 +- vendor/github.com/posener/script/exec.go | 14 +- vendor/github.com/posener/script/from.go | 3 +- vendor/github.com/posener/script/ls.go | 21 +- vendor/github.com/posener/script/modify.go | 5 + vendor/github.com/posener/script/sort.go | 13 +- vendor/github.com/posener/script/stream.go | 11 +- vendor/github.com/posener/script/to.go | 20 +- vendor/github.com/posener/script/wc.go | 10 +- .../testify/assert/assertion_compare.go | 36 +- .../testify/assert/assertion_format.go | 216 +- .../testify/assert/assertion_forward.go | 432 ++-- .../testify/assert/assertion_order.go | 24 +- .../stretchr/testify/assert/assertions.go | 384 +++- .../github.com/stretchr/testify/assert/doc.go | 43 +- .../testify/assert/http_assertions.go | 12 +- vendor/go4.org/intern/LICENSE | 29 - vendor/go4.org/intern/README.md | 19 - vendor/go4.org/intern/intern.go | 183 -- .../netaddr => go4.org/netipx}/.gitignore | 0 .../netaddr => go4.org/netipx}/.gitmodules | 0 .../netaddr => go4.org/netipx}/AUTHORS | 0 .../netaddr => go4.org/netipx}/LICENSE | 0 vendor/go4.org/netipx/README.md | 26 + .../netaddr => go4.org/netipx}/ipset.go | 63 +- .../netaddr => go4.org/netipx}/mask6.go | 2 +- vendor/go4.org/netipx/netipx.go | 584 +++++ .../netaddr => go4.org/netipx}/uint128.go | 34 +- .../unsafe/assume-no-moving-gc/LICENSE | 29 - .../unsafe/assume-no-moving-gc/README.md | 13 - .../assume-no-moving-gc.go | 32 - .../unsafe/assume-no-moving-gc/check.go | 36 - vendor/golang.org/x/exp/LICENSE | 27 + vendor/golang.org/x/exp/PATENTS | 22 + .../x/exp/constraints/constraints.go | 50 + vendor/golang.org/x/exp/slices/cmp.go | 44 + vendor/golang.org/x/exp/slices/slices.go | 499 +++++ vendor/golang.org/x/exp/slices/sort.go | 195 ++ .../golang.org/x/exp/slices/zsortanyfunc.go | 479 ++++ .../golang.org/x/exp/slices/zsortordered.go | 481 +++++ vendor/golang.org/x/sys/unix/fcntl.go | 2 +- vendor/golang.org/x/sys/unix/ioctl_linux.go | 5 + vendor/golang.org/x/sys/unix/mkerrors.sh | 3 +- vendor/golang.org/x/sys/unix/syscall_bsd.go | 2 +- vendor/golang.org/x/sys/unix/syscall_linux.go | 28 +- .../golang.org/x/sys/unix/syscall_openbsd.go | 14 + .../golang.org/x/sys/unix/syscall_solaris.go | 2 +- .../x/sys/unix/syscall_zos_s390x.go | 2 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 2 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 15 + .../x/sys/unix/zsyscall_openbsd_386.go | 26 + .../x/sys/unix/zsyscall_openbsd_386.s | 5 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 26 + .../x/sys/unix/zsyscall_openbsd_amd64.s | 5 + .../x/sys/unix/zsyscall_openbsd_arm.go | 26 + .../x/sys/unix/zsyscall_openbsd_arm.s | 5 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 26 + .../x/sys/unix/zsyscall_openbsd_arm64.s | 5 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 26 + .../x/sys/unix/zsyscall_openbsd_mips64.s | 5 + .../x/sys/unix/zsyscall_openbsd_ppc64.go | 26 + .../x/sys/unix/zsyscall_openbsd_ppc64.s | 6 + .../x/sys/unix/zsyscall_openbsd_riscv64.go | 26 + .../x/sys/unix/zsyscall_openbsd_riscv64.s | 5 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 32 + .../x/sys/windows/syscall_windows.go | 2 + .../x/sys/windows/zsyscall_windows.go | 19 + vendor/inet.af/netaddr/README.md | 46 - vendor/inet.af/netaddr/fuzz.go | 203 -- vendor/inet.af/netaddr/netaddr.go | 1919 ----------------- vendor/modules.txt | 42 +- 109 files changed, 4996 insertions(+), 3891 deletions(-) create mode 100644 vendor/github.com/fatih/color/color_windows.go delete mode 100644 vendor/github.com/mattn/go-colorable/.travis.yml create mode 100644 vendor/github.com/maxmind/mmdbwriter/errors.go delete mode 100644 vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go create mode 100644 vendor/github.com/oschwald/maxminddb-golang/reader_memory.go rename vendor/github.com/oschwald/maxminddb-golang/{reader_other.go => reader_mmap.go} (70%) create mode 100644 vendor/github.com/oschwald/maxminddb-golang/set_zero_120.go create mode 100644 vendor/github.com/oschwald/maxminddb-golang/set_zero_pre120.go delete mode 100644 vendor/go4.org/intern/LICENSE delete mode 100644 vendor/go4.org/intern/README.md delete mode 100644 vendor/go4.org/intern/intern.go rename vendor/{inet.af/netaddr => go4.org/netipx}/.gitignore (100%) rename vendor/{inet.af/netaddr => go4.org/netipx}/.gitmodules (100%) rename vendor/{inet.af/netaddr => go4.org/netipx}/AUTHORS (100%) rename vendor/{inet.af/netaddr => go4.org/netipx}/LICENSE (100%) create mode 100644 vendor/go4.org/netipx/README.md rename vendor/{inet.af/netaddr => go4.org/netipx}/ipset.go (88%) rename vendor/{inet.af/netaddr => go4.org/netipx}/mask6.go (99%) create mode 100644 vendor/go4.org/netipx/netipx.go rename vendor/{inet.af/netaddr => go4.org/netipx}/uint128.go (77%) delete mode 100644 vendor/go4.org/unsafe/assume-no-moving-gc/LICENSE delete mode 100644 vendor/go4.org/unsafe/assume-no-moving-gc/README.md delete mode 100644 vendor/go4.org/unsafe/assume-no-moving-gc/assume-no-moving-gc.go delete mode 100644 vendor/go4.org/unsafe/assume-no-moving-gc/check.go create mode 100644 vendor/golang.org/x/exp/LICENSE create mode 100644 vendor/golang.org/x/exp/PATENTS create mode 100644 vendor/golang.org/x/exp/constraints/constraints.go create mode 100644 vendor/golang.org/x/exp/slices/cmp.go create mode 100644 vendor/golang.org/x/exp/slices/slices.go create mode 100644 vendor/golang.org/x/exp/slices/sort.go create mode 100644 vendor/golang.org/x/exp/slices/zsortanyfunc.go create mode 100644 vendor/golang.org/x/exp/slices/zsortordered.go delete mode 100644 vendor/inet.af/netaddr/README.md delete mode 100644 vendor/inet.af/netaddr/fuzz.go delete mode 100644 vendor/inet.af/netaddr/netaddr.go diff --git a/go.mod b/go.mod index 80e57aa1..ccd2c0b8 100644 --- a/go.mod +++ b/go.mod @@ -3,35 +3,39 @@ module github.com/ipinfo/cli go 1.20 require ( - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.16.0 github.com/hashicorp/go-multierror v1.1.1 github.com/ipinfo/go/v2 v2.10.0 - github.com/ipinfo/mmdbctl v0.0.0-20230726080357-558a20ba8524 + github.com/ipinfo/mmdbctl v0.0.0-20231218070001-af3e28a7cd61 github.com/jszwec/csvutil v1.4.0 github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 - github.com/posener/script v1.1.5 + github.com/posener/script v1.2.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.4 go.etcd.io/bbolt v1.3.6 golang.org/x/term v0.14.0 gopkg.in/yaml.v3 v3.0.1 ) -require golang.org/x/text v0.14.0 // indirect +require ( + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect + golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect + golang.org/x/text v0.14.0 // indirect +) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.9 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/maxmind/mmdbwriter v0.0.0-20220808142708-766ad8188582 // indirect - github.com/oschwald/maxminddb-golang v1.10.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/maxmind/mmdbwriter v1.0.1-0.20231024181307-469cd9b959b4 // indirect + github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go4.org/intern v0.0.0-20220617035311-6925f38cc365 // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect golang.org/x/net v0.18.0 golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect inet.af/netaddr v0.0.0-20220811202034-502d2d690317 // indirect ) diff --git a/go.sum b/go.sum index 79e8db0c..b4d60c47 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -18,17 +20,28 @@ github.com/ipinfo/go/v2 v2.10.0 h1:v9sFjaxnVVD+JVgpWpjgwols18Tuu4SgBDaHHaw0IXo= github.com/ipinfo/go/v2 v2.10.0/go.mod h1:tRDkYfM20b1XzNqorn1Q1O6Xtg7uzw3Wn3I2R0SyJh4= github.com/ipinfo/mmdbctl v0.0.0-20230726080357-558a20ba8524 h1:om+KMCwwLE1scrxr5YirYikcgl27Z2KbKQSpobt/2b0= github.com/ipinfo/mmdbctl v0.0.0-20230726080357-558a20ba8524/go.mod h1:RVULurqCcBRklgMU3st4j+sIEuVNY+mB1IMhhi/wjLA= +github.com/ipinfo/mmdbctl v0.0.0-20231218070001-af3e28a7cd61 h1:AZ4d7ISShmWhXvYlQ+i7M8CQi18oAnMZ0BzIS41GaQ0= +github.com/ipinfo/mmdbctl v0.0.0-20231218070001-af3e28a7cd61/go.mod h1:wmTzmgyq7sWTQDrHBU1lqeSXTsElojhxEYC5xCHWclA= github.com/jszwec/csvutil v1.4.0 h1:ro7gZN8PRsyNUEX8qE/eYPE5/kffEXMs+4eRcOd1oUk= github.com/jszwec/csvutil v1.4.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg= github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/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/maxmind/mmdbwriter v0.0.0-20220808142708-766ad8188582 h1:MDmZuAhYcKmNKqMpOziP0TIItFt1FkmkpAoBuSSVuHk= github.com/maxmind/mmdbwriter v0.0.0-20220808142708-766ad8188582/go.mod h1:y4XM3HDhC+YidMZGlJw0PbmXNnRZsPHHLyzDHbcS4l8= +github.com/maxmind/mmdbwriter v1.0.1-0.20231024181307-469cd9b959b4 h1:rF6qXloekm+zWpzca/SrkgVOikFSxLBEPC1TdBEsDCM= +github.com/maxmind/mmdbwriter v1.0.1-0.20231024181307-469cd9b959b4/go.mod h1:6F/4tSDsJ8Y9UFVnehdZEIS220Uz62E7lbo8ZS0DehI= github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= @@ -38,6 +51,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/script v1.1.5 h1:su+9YHNlevT+Hlq2Xul5skh5kYDIBE+x4xu+5mLDT9o= github.com/posener/script v1.1.5/go.mod h1:Rg3ijooqulo05aGLyGsHoLmIOUzHUVK19WVgrYBPU/E= +github.com/posener/script v1.2.0 h1:DrZz0qFT8lCLkYNi1PleLDANFnKxJ2VmlNPJbAkVLsE= +github.com/posener/script v1.2.0/go.mod h1:s4sVvRXtdc/1aK6otTSeW2BVXndO8MsoOVUwK74zcg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -46,12 +61,16 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= go4.org/intern v0.0.0-20220617035311-6925f38cc365 h1:t9hFvR102YlOqU0fQn1wgwhNvSbHGBbbJxX9JKfU3l0= go4.org/intern v0.0.0-20220617035311-6925f38cc365/go.mod h1:WXRv3p7T6gzt0CcJm43AAKdKVZmcQbwwC7EwquU5BZU= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 h1:WJhcL4p+YeDxmZWg141nRm7XC8IDmhz7lk5GpadO1Sg= @@ -59,6 +78,8 @@ go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2/go.mod h1: golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -80,8 +101,11 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md index 5152bf59..be82827c 100644 --- a/vendor/github.com/fatih/color/README.md +++ b/vendor/github.com/fatih/color/README.md @@ -7,7 +7,6 @@ suits you. ![Color](https://user-images.githubusercontent.com/438920/96832689-03b3e000-13f4-11eb-9803-46f4c4de3406.jpg) - ## Install ```bash @@ -124,17 +123,17 @@ fmt.Println("All text will now be bold magenta.") ``` ### Disable/Enable color - + There might be a case where you want to explicitly disable/enable color output. the `go-isatty` package will automatically disable color output for non-tty output streams (for example if the output were piped directly to `less`). The `color` package also disables color output if the [`NO_COLOR`](https://no-color.org) environment -variable is set (regardless of its value). +variable is set to a non-empty string. -`Color` has support to disable/enable colors programatically both globally and +`Color` has support to disable/enable colors programmatically both globally and for single color definitions. For example suppose you have a CLI app and a -`--no-color` bool flag. You can easily disable the color output with: +`-no-color` bool flag. You can easily disable the color output with: ```go var flagNoColor = flag.Bool("no-color", false, "Disable color output") @@ -167,11 +166,10 @@ To output color in GitHub Actions (or other CI systems that support ANSI colors) * Save/Return previous values * Evaluate fmt.Formatter interface - ## Credits - * [Fatih Arslan](https://github.com/fatih) - * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) +* [Fatih Arslan](https://github.com/fatih) +* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) ## License diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index 98a60f3c..c4234287 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -19,10 +19,10 @@ var ( // set (regardless of its value). This is a global option and affects all // colors. For more control over each color block use the methods // DisableColor() individually. - NoColor = noColorExists() || os.Getenv("TERM") == "dumb" || + NoColor = noColorIsSet() || os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) - // Output defines the standard output of the print functions. By default + // Output defines the standard output of the print functions. By default, // os.Stdout is used. Output = colorable.NewColorableStdout() @@ -35,10 +35,9 @@ var ( colorsCacheMu sync.Mutex // protects colorsCache ) -// noColorExists returns true if the environment variable NO_COLOR exists. -func noColorExists() bool { - _, exists := os.LookupEnv("NO_COLOR") - return exists +// noColorIsSet returns true if the environment variable NO_COLOR is set to a non-empty string. +func noColorIsSet() bool { + return os.Getenv("NO_COLOR") != "" } // Color defines a custom color object which is defined by SGR parameters. @@ -66,6 +65,29 @@ const ( CrossedOut ) +const ( + ResetBold Attribute = iota + 22 + ResetItalic + ResetUnderline + ResetBlinking + _ + ResetReversed + ResetConcealed + ResetCrossedOut +) + +var mapResetAttributes map[Attribute]Attribute = map[Attribute]Attribute{ + Bold: ResetBold, + Faint: ResetBold, + Italic: ResetItalic, + Underline: ResetUnderline, + BlinkSlow: ResetBlinking, + BlinkRapid: ResetBlinking, + ReverseVideo: ResetReversed, + Concealed: ResetConcealed, + CrossedOut: ResetCrossedOut, +} + // Foreground text colors const ( FgBlack Attribute = iota + 30 @@ -120,7 +142,7 @@ func New(value ...Attribute) *Color { params: make([]Attribute, 0), } - if noColorExists() { + if noColorIsSet() { c.noColor = boolPtr(true) } @@ -152,7 +174,7 @@ func (c *Color) Set() *Color { return c } - fmt.Fprintf(Output, c.format()) + fmt.Fprint(Output, c.format()) return c } @@ -164,16 +186,21 @@ func (c *Color) unset() { Unset() } -func (c *Color) setWriter(w io.Writer) *Color { +// SetWriter is used to set the SGR sequence with the given io.Writer. This is +// a low-level function, and users should use the higher-level functions, such +// as color.Fprint, color.Print, etc. +func (c *Color) SetWriter(w io.Writer) *Color { if c.isNoColorSet() { return c } - fmt.Fprintf(w, c.format()) + fmt.Fprint(w, c.format()) return c } -func (c *Color) unsetWriter(w io.Writer) { +// UnsetWriter resets all escape attributes and clears the output with the give +// io.Writer. Usually should be called after SetWriter(). +func (c *Color) UnsetWriter(w io.Writer) { if c.isNoColorSet() { return } @@ -192,20 +219,14 @@ func (c *Color) Add(value ...Attribute) *Color { return c } -func (c *Color) prepend(value Attribute) { - c.params = append(c.params, 0) - copy(c.params[1:], c.params[0:]) - c.params[0] = value -} - // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprint(w, a...) } @@ -227,8 +248,8 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprintf(w, format, a...) } @@ -248,10 +269,7 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) - - return fmt.Fprintln(w, a...) + return fmt.Fprintln(w, c.wrap(fmt.Sprint(a...))) } // Println formats using the default formats for its operands and writes to @@ -260,10 +278,7 @@ func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { // encountered. This is the standard fmt.Print() method wrapped with the given // color. func (c *Color) Println(a ...interface{}) (n int, err error) { - c.Set() - defer c.unset() - - return fmt.Fprintln(Output, a...) + return fmt.Fprintln(Output, c.wrap(fmt.Sprint(a...))) } // Sprint is just like Print, but returns a string instead of printing it. @@ -273,7 +288,7 @@ func (c *Color) Sprint(a ...interface{}) string { // Sprintln is just like Println, but returns a string instead of printing it. func (c *Color) Sprintln(a ...interface{}) string { - return c.wrap(fmt.Sprintln(a...)) + return fmt.Sprintln(c.Sprint(a...)) } // Sprintf is just like Printf, but returns a string instead of printing it. @@ -355,7 +370,7 @@ func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { // string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintlnFunc() func(a ...interface{}) string { return func(a ...interface{}) string { - return c.wrap(fmt.Sprintln(a...)) + return fmt.Sprintln(c.Sprint(a...)) } } @@ -385,7 +400,18 @@ func (c *Color) format() string { } func (c *Color) unformat() string { - return fmt.Sprintf("%s[%dm", escape, Reset) + //return fmt.Sprintf("%s[%dm", escape, Reset) + //for each element in sequence let's use the speficic reset escape, ou the generic one if not found + format := make([]string, len(c.params)) + for i, v := range c.params { + format[i] = strconv.Itoa(int(Reset)) + ra, ok := mapResetAttributes[v] + if ok { + format[i] = strconv.Itoa(int(ra)) + } + } + + return fmt.Sprintf("%s[%sm", escape, strings.Join(format, ";")) } // DisableColor disables the color output. Useful to not change any existing @@ -396,7 +422,7 @@ func (c *Color) DisableColor() { } // EnableColor enables the color output. Use it in conjunction with -// DisableColor(). Otherwise this method has no side effects. +// DisableColor(). Otherwise, this method has no side effects. func (c *Color) EnableColor() { c.noColor = boolPtr(false) } @@ -413,6 +439,12 @@ func (c *Color) isNoColorSet() bool { // Equals returns a boolean value indicating whether two colors are equal. func (c *Color) Equals(c2 *Color) bool { + if c == nil && c2 == nil { + return true + } + if c == nil || c2 == nil { + return false + } if len(c.params) != len(c2.params) { return false } diff --git a/vendor/github.com/fatih/color/color_windows.go b/vendor/github.com/fatih/color/color_windows.go new file mode 100644 index 00000000..be01c558 --- /dev/null +++ b/vendor/github.com/fatih/color/color_windows.go @@ -0,0 +1,19 @@ +package color + +import ( + "os" + + "golang.org/x/sys/windows" +) + +func init() { + // Opt-in for ansi color support for current process. + // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#output-sequences + var outMode uint32 + out := windows.Handle(os.Stdout.Fd()) + if err := windows.GetConsoleMode(out, &outMode); err != nil { + return + } + outMode |= windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING + _ = windows.SetConsoleMode(out, outMode) +} diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index 04541de7..9491ad54 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -5,106 +5,105 @@ that suits you. Use simple and default helper functions with predefined foreground colors: - color.Cyan("Prints text in cyan.") + color.Cyan("Prints text in cyan.") - // a newline will be appended automatically - color.Blue("Prints %s in blue.", "text") + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") - // More default foreground colors.. - color.Red("We have red") - color.Yellow("Yellow color too!") - color.Magenta("And many others ..") + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") - // Hi-intensity colors - color.HiGreen("Bright green color.") - color.HiBlack("Bright black means gray..") - color.HiWhite("Shiny white color!") + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") -However there are times where custom color mixes are required. Below are some +However, there are times when custom color mixes are required. Below are some examples to create custom color objects and use the print functions of each separate color object. - // Create a new color object - c := color.New(color.FgCyan).Add(color.Underline) - c.Println("Prints cyan text with an underline.") + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") - // Or just add them to New() - d := color.New(color.FgCyan, color.Bold) - d.Printf("This prints bold cyan %s\n", "too!.") + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") - // Mix up foreground and background colors, create new mixes! - red := color.New(color.FgRed) + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) - boldRed := red.Add(color.Bold) - boldRed.Println("This will print text in bold red.") + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") - whiteBackground := red.Add(color.BgWhite) - whiteBackground.Println("Red text with White background.") + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") - // Use your own io.Writer output - color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") - blue := color.New(color.FgBlue) - blue.Fprint(myWriter, "This will print text in blue.") + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: - // Create a custom print function for convenient - red := color.New(color.FgRed).PrintfFunc() - red("warning") - red("error: %s", err) + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) - // Mix up multiple attributes - notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() - notice("don't forget this...") + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") You can also FprintXxx functions to pass your own io.Writer: - blue := color.New(FgBlue).FprintfFunc() - blue(myWriter, "important notice: %s", stars) - - // Mix up with multiple attributes - success := color.New(color.Bold, color.FgGreen).FprintlnFunc() - success(myWriter, don't forget this...") + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") Or create SprintXxx functions to mix strings with other non-colorized strings: - yellow := New(FgYellow).SprintFunc() - red := New(FgRed).SprintFunc() + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() - fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Printf("this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) Windows support is enabled by default. All Print functions work as intended. -However only for color.SprintXXX functions, user should use fmt.FprintXXX and +However, only for color.SprintXXX functions, user should use fmt.FprintXXX and set the output to color.Output: - fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) Using with existing code is possible. Just use the Set() method to set the standard output to the given parameters. That way a rewrite of an existing code is not required. - // Use handy standard colors. - color.Set(color.FgYellow) + // Use handy standard colors. + color.Set(color.FgYellow) - fmt.Println("Existing text will be now in Yellow") - fmt.Printf("This one %s\n", "too") + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") - color.Unset() // don't forget to unset + color.Unset() // don't forget to unset - // You can mix up parameters - color.Set(color.FgMagenta, color.Bold) - defer color.Unset() // use it in your function + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function - fmt.Println("All text will be now bold magenta.") + fmt.Println("All text will be now bold magenta.") There might be a case where you want to disable color output (for example to pipe the standard output of your app to somewhere else). `Color` has support to @@ -112,24 +111,24 @@ disable colors both globally and for single color definition. For example suppose you have a CLI app and a `--no-color` bool flag. You can easily disable the color output with: - var flagNoColor = flag.Bool("no-color", false, "Disable color output") + var flagNoColor = flag.Bool("no-color", false, "Disable color output") - if *flagNoColor { - color.NoColor = true // disables colorized output - } + if *flagNoColor { + color.NoColor = true // disables colorized output + } You can also disable the color by setting the NO_COLOR environment variable to any value. It also has support for single color definitions (local). You can disable/enable color output on the fly: - c := color.New(color.FgCyan) - c.Println("Prints cyan text") + c := color.New(color.FgCyan) + c.Println("Prints cyan text") - c.DisableColor() - c.Println("This is printed without any color") + c.DisableColor() + c.Println("This is printed without any color") - c.EnableColor() - c.Println("This prints again cyan...") + c.EnableColor() + c.Println("This prints again cyan...") */ package color diff --git a/vendor/github.com/ipinfo/mmdbctl/lib/cmd_import.go b/vendor/github.com/ipinfo/mmdbctl/lib/cmd_import.go index f7568a33..4084d0f1 100644 --- a/vendor/github.com/ipinfo/mmdbctl/lib/cmd_import.go +++ b/vendor/github.com/ipinfo/mmdbctl/lib/cmd_import.go @@ -12,6 +12,7 @@ import ( "path/filepath" "strings" + "github.com/ipinfo/cli/lib/iputil" "github.com/maxmind/mmdbwriter" "github.com/maxmind/mmdbwriter/inserter" "github.com/maxmind/mmdbwriter/mmdbtype" @@ -238,7 +239,7 @@ func CmdImport(f CmdImportFlags, args []string, printHelp func()) error { fieldSrcCnt += 1 } if fieldSrcCnt > 1 { - return errors.New("conflicting field sources specified.") + return errors.New("conflicting field sources specified") } if f.NoFields { f.Fields = []string{} @@ -502,10 +503,18 @@ func ParseCSVHeaders(parts []string, f *CmdImportFlags, dataColStart *int) { } func AppendCSVRecord(f CmdImportFlags, dataColStart int, delim rune, parts []string, tree *mmdbwriter.Tree) error { + if startIp, _ := iputil.DecimalStrToIP(parts[0], false); startIp != nil { + parts[0] = startIp.String() + } + networkStr := parts[0] // convert 2 IPs into IP range? if f.RangeMultiCol { + if endIp, _ := iputil.DecimalStrToIP(parts[1], false); endIp != nil { + parts[1] = endIp.String() + } + networkStr = parts[0] + "-" + parts[1] } diff --git a/vendor/github.com/ipinfo/mmdbctl/lib/cmd_read.go b/vendor/github.com/ipinfo/mmdbctl/lib/cmd_read.go index 856820a4..1652c1a4 100644 --- a/vendor/github.com/ipinfo/mmdbctl/lib/cmd_read.go +++ b/vendor/github.com/ipinfo/mmdbctl/lib/cmd_read.go @@ -7,7 +7,7 @@ import ( "os" "github.com/fatih/color" - "github.com/ipinfo/cli/lib" + "github.com/ipinfo/cli/lib/iputil" "github.com/oschwald/maxminddb-golang" "github.com/spf13/pflag" ) @@ -85,7 +85,7 @@ func CmdRead(f CmdReadFlags, args []string, printHelp func()) error { defer db.Close() // get IP list. - ips, err := lib.IPListFromAllSrcs(args[:len(args)-1]) + ips, err := iputil.IPListFromAllSrcs(args[:len(args)-1]) if err != nil { return fmt.Errorf("couldn't get IP list: %w", err) } diff --git a/vendor/github.com/mattn/go-colorable/.travis.yml b/vendor/github.com/mattn/go-colorable/.travis.yml deleted file mode 100644 index 7942c565..00000000 --- a/vendor/github.com/mattn/go-colorable/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go -sudo: false -go: - - 1.13.x - - tip - -before_install: - - go get -t -v ./... - -script: - - ./go.test.sh - -after_success: - - bash <(curl -s https://codecov.io/bash) - diff --git a/vendor/github.com/mattn/go-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md index e055952b..ca048371 100644 --- a/vendor/github.com/mattn/go-colorable/README.md +++ b/vendor/github.com/mattn/go-colorable/README.md @@ -1,6 +1,6 @@ # go-colorable -[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable) +[![Build Status](https://github.com/mattn/go-colorable/workflows/test/badge.svg)](https://github.com/mattn/go-colorable/actions?query=workflow%3Atest) [![Codecov](https://codecov.io/gh/mattn/go-colorable/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-colorable) [![GoDoc](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable) [![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable) diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go index 1f7806fe..416d1bbb 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_appengine.go +++ b/vendor/github.com/mattn/go-colorable/colorable_appengine.go @@ -1,3 +1,4 @@ +//go:build appengine // +build appengine package colorable diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go index 08cbd1e0..766d9460 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -1,5 +1,5 @@ -// +build !windows -// +build !appengine +//go:build !windows && !appengine +// +build !windows,!appengine package colorable diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 41215d7f..1846ad5a 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -1,5 +1,5 @@ -// +build windows -// +build !appengine +//go:build windows && !appengine +// +build windows,!appengine package colorable @@ -452,18 +452,22 @@ func (w *Writer) Write(data []byte) (n int, err error) { } else { er = bytes.NewReader(data) } - var bw [1]byte + var plaintext bytes.Buffer loop: for { c1, err := er.ReadByte() if err != nil { + plaintext.WriteTo(w.out) break loop } if c1 != 0x1b { - bw[0] = c1 - w.out.Write(bw[:]) + plaintext.WriteByte(c1) continue } + _, err = plaintext.WriteTo(w.out) + if err != nil { + break loop + } c2, err := er.ReadByte() if err != nil { break loop diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go index 2dcb09aa..05d6f74b 100644 --- a/vendor/github.com/mattn/go-colorable/noncolorable.go +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -18,21 +18,22 @@ func NewNonColorable(w io.Writer) io.Writer { // Write writes data on console func (w *NonColorable) Write(data []byte) (n int, err error) { er := bytes.NewReader(data) - var bw [1]byte + var plaintext bytes.Buffer loop: for { c1, err := er.ReadByte() if err != nil { + plaintext.WriteTo(w.out) break loop } if c1 != 0x1b { - bw[0] = c1 - _, err = w.out.Write(bw[:]) - if err != nil { - break loop - } + plaintext.WriteByte(c1) continue } + _, err = plaintext.WriteTo(w.out) + if err != nil { + break loop + } c2, err := er.ReadByte() if err != nil { break loop @@ -41,7 +42,6 @@ loop: continue } - var buf bytes.Buffer for { c, err := er.ReadByte() if err != nil { @@ -50,7 +50,6 @@ loop: if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { break } - buf.Write([]byte(string(c))) } } diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index 39bbcf00..d0ea68f4 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) && !appengine -// +build darwin freebsd openbsd netbsd dragonfly +//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 31503226..7402e061 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 67787657..0337d8cf 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/github.com/maxmind/mmdbwriter/.golangci.toml b/vendor/github.com/maxmind/mmdbwriter/.golangci.toml index f1deedaf..648ec47a 100644 --- a/vendor/github.com/maxmind/mmdbwriter/.golangci.toml +++ b/vendor/github.com/maxmind/mmdbwriter/.golangci.toml @@ -1,29 +1,34 @@ [run] - deadline = "10m" - - tests = true +deadline = "10m" +tests = true [linters] - disable-all = true - enable = [ +disable-all = true +enable = [ + "asasalint", "asciicheck", "bidichk", "bodyclose", "containedctx", "contextcheck", - "deadcode", "depguard", + # This is probably worthwhile, but there are a number of false positives + # that would need to be addressed. + # "dupword", "durationcheck", "errcheck", "errchkjson", "errname", "errorlint", - # Causes a panic. + # This doesn't seem to know about CTEs or DELETEs with RETURNING # "execinquery", "exhaustive", + # We often don't initialize all of the struct fields. This is fine + # generally + # "exhaustruct", "exportloopref", "forbidigo", - # We tried this liner but most places we do forced type asserts are + # We tried this linter but most places we do forced type asserts are # pretty safe, e.g., an atomic.Value when everything is encapsulated # in a small package. # "forcetypeassert", @@ -35,18 +40,35 @@ "gomodguard", "gosec", "gosimple", + # This only "caught" one thing, and it seemed like a reasonable use + # of Han script. Generally, I don't think we want to prevent the use + # of particulr scripts. The time.Local checks might be useful, but + # this didn't actually catch anything of note there. + # "gosmopolitan", + # Similar to the exhaustive linter and I don't know that we use these + # sorts of sum types + # "gochecksumtype". "govet", "grouper", + # Seems too opinionated or at least would require going through all the + # interfaces we have. + # "inamedparam" "ineffassign", "lll", + # We don't use these loggers + # "loggercheck", "makezero", # Maintainability Index. Seems like it could be a good idea, but a # lot of things fail and we would need to make some decisions about # what to allow. # "maintidx", "misspell", + # Causes panics, e.g., when processing mmerrors + # "musttag", "nakedret", "nilerr", + # Perhaps too opinionated. We do have some legitimate uses of "return nil, nil" + # "nilnil", "noctx", "nolintlint", # We occasionally use named returns for documentation, which is helpful. @@ -55,558 +77,695 @@ # case. # "nonamedreturns", "nosprintfhostport", + "perfsprint", "predeclared", + "protogetter", "revive", "rowserrcheck", # https://github.com/golangci/golangci-lint/issues/287 # "safesql", + "sloglint", "sqlclosecheck", "staticcheck", - "structcheck", "stylecheck", + # We have very few structs with multiple tags and for the couple we had, this + # actually made it harder to read. + # "tagalign", "tenv", + "testifylint", "tparallel", "typecheck", "unconvert", "unparam", "unused", - "varcheck", + "usestdlibvars", "vetshadow", "wastedassign", # We don't currently wrap external errors in this module. # "wrapcheck", - ] +] # Please note that we only use depguard for stdlib as gomodguard only # supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12 -[linters-settings.depguard] - list-type = "blacklist" - include-go-root = true - packages = [ - # ioutil is deprecated. The functions have been moved elsewhere: - # https://golang.org/doc/go1.16#ioutil - "io/ioutil", - ] +[[linters-settings.depguard.rules.main.deny]] +pkg = "io/ioutil" +desc = "Deprecated. Functions have been moved elsewhere." + +[[linters-settings.depguard.rules.main.deny]] +# slices has better alternatives. +pkg = "sort" +desc = "Use slices instead" [linters-settings.errcheck] - # Don't allow setting of error to the blank identifier. If there is a legtimate - # reason, there should be a nolint with an explanation. - check-blank = true +# Don't allow setting of error to the blank identifier. If there is a legitimate +# reason, there should be a nolint with an explanation. +check-blank = true - exclude-functions = [ - # If we are rolling back a transaction, we are often already in an error - # state. - '(*database/sql.Tx).Rollback', +exclude-functions = [ + # If we are rolling back a transaction, we are often already in an error + # state. + '(*database/sql.Tx).Rollback', - # It is reasonable to ignore errors if Cleanup fails in most cases. - '(*github.com/google/renameio/v2.PendingFile).Cleanup', + # It is reasonable to ignore errors if Cleanup fails in most cases. + '(*github.com/google/renameio/v2.PendingFile).Cleanup', - # We often don't care if removing a file failed (e.g., it doesn't exist) - 'os.Remove', - 'os.RemoveAll', - ] + # We often don't care if removing a file failed (e.g., it doesn't exist) + 'os.Remove', + 'os.RemoveAll', +] - # Ignoring Close so that we don't have to have a bunch of - # `defer func() { _ = r.Close() }()` constructs when we - # don't actually care about the error. - ignore = "Close,fmt:.*" +# Ignoring Close so that we don't have to have a bunch of +# `defer func() { _ = r.Close() }()` constructs when we +# don't actually care about the error. +ignore = "Close,fmt:.*" [linters-settings.errorlint] - errorf = true - asserts = true - comparison = true +errorf = true +asserts = true +comparison = true [linters-settings.exhaustive] - default-signifies-exhaustive = true +default-signifies-exhaustive = true [linters-settings.forbidigo] - # Forbid the following identifiers - forbid = [ - "^minFraud*", - "^maxMind*", - ] +# Forbid the following identifiers +forbid = [ + { p = "Geoip", msg = "you should use `GeoIP`" }, + { p = "^geoIP", msg = "you should use `geoip`" }, + { p = "^hubSpot", msg = "you should use `hubspot`" }, + { p = "Maxmind", msg = "you should use `MaxMind`" }, + { p = "^maxMind", msg = "you should use `maxmind`" }, + { p = "Minfraud", msg = "you should use `MinFraud`" }, + { p = "^minFraud", msg = "you should use `minfraud`" }, + { p = "[Uu]ser[iI][dD]", msg = "you should use `accountID` or `AccountID`" }, + { p = "WithEnterpriseURLs", msg = "Use ghe.NewClient instead." }, + { p = "^bigquery.NewClient", msg = "you should use mmgcloud.NewBigQueryClient instead." }, + { p = "^cloudresourcemanager.NewService", msg = "you should use mmgcloud.NewCloudResourceManagerService instead." }, + { p = "^compute.NewService", msg = "you should use mmgcloud.NewComputeService instead." }, + { p = "^drive.NewService", msg = "you should use mmgdrive.NewGDrive instead." }, + { p = "^math.Max$", msg = "you should use the max built-in instead." }, + { p = "^math.Min$", msg = "you should use the min built-in instead." }, + { p = "^net.ParseCIDR", msg = "you should use netip.ParsePrefix unless you really need a *net.IPNet" }, + { p = "^net.ParseIP", msg = "you should use netip.ParseAddr unless you really need a net.IP" }, + { p = "^pgtype.NewMap", msg = "you should use mmdatabase.NewTypeMap instead" }, + { p = "^serviceusage.NewService", msg = "you should use mmgcloud.NewServiceUsageService instead." }, + { p = "^sheets.NewService", msg = "you should use mmgcloud.NewSheetsService instead." }, + { p = "^storage.NewClient", msg = "you should use mmgcloud.NewGStorageClient instead. This sets the HTTP client settings that we need for internal use." }, + { p = "^os.IsNotExist", msg = "As per their docs, new code should use errors.Is(err, fs.ErrNotExist)." }, + { p = "^os.IsExist", msg = "As per their docs, new code should use errors.Is(err, fs.ErrExist)" }, + { p = "^net.LookupIP", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupCNAME", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupHost", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupPort", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupTXT", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupAddr", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupMX", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupNS", msg = "You should use net.Resolver functions instead." }, + { p = "^net.LookupSRV", msg = "You should use net.Resolver functions instead." }, +] [linters-settings.gocritic] - enabled-checks = [ - "appendAssign", - "appendCombine", - "argOrder", - "assignOp", - "badCall", - "badCond", - "badLock", - "badRegexp", - "badSorting", - "boolExprSimplify", - "builtinShadow", - "builtinShadowDecl", - "captLocal", - "caseOrder", - "codegenComment", - "commentedOutCode", - "commentedOutImport", - "commentFormatting", - "defaultCaseOrder", - # Revive's defer rule already captures this. This caught no extra cases. - # "deferInLoop", - "deferUnlambda", - "deprecatedComment", - "docStub", - "dupArg", - "dupBranchBody", - "dupCase", - "dupImport", - "dupSubExpr", - "dynamicFmtString", - "elseif", - "emptyDecl", - "emptyFallthrough", - "emptyStringTest", - "equalFold", - "evalOrder", - "exitAfterDefer", - "exposedSyncMutex", - "externalErrorReassign", - # Given that all of our code runs on Linux and the / separate should - # work fine, this seems less important. - # "filepathJoin", - "flagDeref", - "flagName", - "hexLiteral", - "ifElseChain", - "importShadow", - "indexAlloc", - "initClause", - "ioutilDeprecated", - "mapKey", - "methodExprCall", - "nestingReduce", - "newDeref", - "nilValReturn", - "octalLiteral", - "offBy1", - "paramTypeCombine", - "preferDecodeRune", - "preferFilepathJoin", - "preferFprint", - "preferStringWriter", - "preferWriteByte", - "ptrToRefParam", - "rangeExprCopy", - "rangeValCopy", - "redundantSprint", - "regexpMust", - "regexpPattern", - # This might be good, but I don't think we want to encourage - # significant changes to regexes as we port stuff from Perl. - # "regexpSimplify", - "ruleguard", - "singleCaseSwitch", - "sliceClear", - "sloppyLen", - # This seems like it might also be good, but a lot of existing code - # fails. - # "sloppyReassign", - "returnAfterHttpError", - "sloppyTypeAssert", - "sortSlice", - "sprintfQuotedString", - "sqlQuery", - "stringsCompare", - "stringXbytes", - "switchTrue", - "syncMapLoadAndDelete", - "timeExprSimplify", - "todoCommentWithoutDetail", - "tooManyResultsChecker", - "truncateCmp", - "typeAssertChain", - "typeDefFirst", - "typeSwitchVar", - "typeUnparen", - "underef", - "unlabelStmt", - "unlambda", - # I am not sure we would want this linter and a lot of existing - # code fails. - # "unnamedResult", - "unnecessaryBlock", - "unnecessaryDefer", - "unslice", - "valSwap", - "weakCond", - "wrapperFunc", - "yodaStyleExpr", - # This requires explanations for "nolint" directives. This would be - # nice for gosec ones, but I am not sure we want it generally unless - # we can get the false positive rate lower. - # "whyNoLint" - ] +enabled-checks = [ + "appendAssign", + "appendCombine", + "argOrder", + "assignOp", + "badCall", + "badCond", + "badLock", + "badRegexp", + "badSorting", + "boolExprSimplify", + "builtinShadow", + "builtinShadowDecl", + "captLocal", + "caseOrder", + "codegenComment", + "commentedOutCode", + "commentedOutImport", + "commentFormatting", + "defaultCaseOrder", + # Revive's defer rule already captures this. This caught no extra cases. + # "deferInLoop", + "deferUnlambda", + "deprecatedComment", + "docStub", + "dupArg", + "dupBranchBody", + "dupCase", + "dupImport", + "dupSubExpr", + "dynamicFmtString", + "elseif", + "emptyDecl", + "emptyFallthrough", + "emptyStringTest", + "equalFold", + "evalOrder", + "exitAfterDefer", + "exposedSyncMutex", + "externalErrorReassign", + # Given that all of our code runs on Linux and the / separate should + # work fine, this seems less important. + # "filepathJoin", + "flagDeref", + "flagName", + "hexLiteral", + # This seems like it could be good, but we would need to update current + # uses. It supports "--fix", but the fixing is a bit broken. + # "httpNoBody", + # This might be good, but we would have to revisit a lot of code. + # "hugeParam", + "ifElseChain", + "importShadow", + "indexAlloc", + "initClause", + "mapKey", + "methodExprCall", + "nestingReduce", + "newDeref", + "nilValReturn", + "octalLiteral", + "offBy1", + "paramTypeCombine", + "preferDecodeRune", + "preferFilepathJoin", + "preferFprint", + "preferStringWriter", + "preferWriteByte", + "ptrToRefParam", + "rangeExprCopy", + "rangeValCopy", + "redundantSprint", + "regexpMust", + "regexpPattern", + # This might be good, but I don't think we want to encourage + # significant changes to regexes as we port stuff from Perl. + # "regexpSimplify", + "returnAfterHttpError", + "ruleguard", + "singleCaseSwitch", + "sliceClear", + "sloppyLen", + # This seems like it might also be good, but a lot of existing code + # fails. + # "sloppyReassign", + # This complains about helper functions in tests. + # "sloppyTestFuncName", + "sloppyTypeAssert", + "sortSlice", + "sprintfQuotedString", + "sqlQuery", + "stringsCompare", + "stringConcatSimplify", + "stringXbytes", + "switchTrue", + "syncMapLoadAndDelete", + "timeExprSimplify", + "todoCommentWithoutDetail", + "tooManyResultsChecker", + "truncateCmp", + "typeAssertChain", + "typeDefFirst", + "typeSwitchVar", + "typeUnparen", + "underef", + "unlabelStmt", + "unlambda", + # I am not sure we would want this linter and a lot of existing + # code fails. + # "unnamedResult", + "unnecessaryBlock", + "unnecessaryDefer", + "unslice", + "valSwap", + "weakCond", + # Covered by nolintlint + # "whyNoLint" + "wrapperFunc", + "yodaStyleExpr", +] [linters-settings.gofumpt] - extra-rules = true - lang-version = "1.17" +extra-rules = true +lang-version = "1.18" [linters-settings.gomodguard] - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/avct/uasurfer"] - recommendations = ["github.com/xavivars/uasurfer"] - reason = "The original avct module appears abandoned." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/BurntSushi/toml"] - recommendations = ["github.com/pelletier/go-toml/v2"] - reason = "This library panics frequently on invalid input." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/gofrs/uuid"] - recommendations = ["github.com/google/uuid"] - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/satori/go.uuid"] - recommendations = ["github.com/google/uuid"] - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/lib/pq"] - recommendations = ["github.com/jackc/pgx"] - reason = "This library is no longer actively maintained." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/neilotoole/errgroup"] - recommendations = ["golang.org/x/sync/errgroup"] - reason = "This library can lead to subtle deadlocks in certain use cases." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/pariz/gountries"] - reason = "This library's data is not actively maintained. Use GeoInfo data." - - [linters-settings.gomodguard.blocked.modules."github.com/pkg/errors"] - reason = "pkg/errors is no longer maintained." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/RackSec/srslog"] - recommendations = ["github.com/RackSec/srslog"] - reason = "This library's data is not actively maintained." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/ua-parser/uap-go/uaparser"] - recommendations = ["github.com/xavivars/uasurfer"] - reason = "The performance of this library is absolutely abysmal." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."github.com/ugorji/go/codec"] - recommendations = ["encoding/json", "github.com/mailru/easyjson"] - reason = "This library is poorly maintained. We should default to using encoding/json and use easyjson where performance really matters." - - [[linters-settings.gomodguard.blocked.modules]] - [linters-settings.gomodguard.blocked.modules."io/ioutil"] - - [[linters-settings.gomodguard.blocked.versions]] - [linters-settings.gomodguard.blocked.versions."github.com/jackc/pgx"] - version = "< 4.0.0" - reason = "Use github.com/jackc/pgx/v4" +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/avct/uasurfer"] +recommendations = ["github.com/xavivars/uasurfer"] +reason = "The original avct module appears abandoned." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/BurntSushi/toml"] +recommendations = ["github.com/pelletier/go-toml/v2"] +reason = "This library panics frequently on invalid input." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/pelletier/go-toml"] +recommendations = ["github.com/pelletier/go-toml/v2"] +reason = "This is an outdated version." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/gofrs/uuid"] +recommendations = ["github.maxmind.com/maxmind/mm_website/go/pkg/uuid"] + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/gofrs/uuid/v5"] +recommendations = ["github.maxmind.com/maxmind/mm_website/go/pkg/uuid"] + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/satori/go.uuid"] +recommendations = ["github.maxmind.com/maxmind/mm_website/go/pkg/uuid"] + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/google/uuid"] +recommendations = ["github.maxmind.com/maxmind/mm_website/go/pkg/uuid"] + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/lib/pq"] +recommendations = ["github.com/jackc/pgx"] +reason = "This library is no longer actively maintained." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/neilotoole/errgroup"] +recommendations = ["golang.org/x/sync/errgroup"] +reason = "This library can lead to subtle deadlocks in certain use cases." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/pariz/gountries"] +reason = "This library's data is not actively maintained. Use GeoInfo data." + +[linters-settings.gomodguard.blocked.modules."github.com/pkg/errors"] +reason = "pkg/errors is no longer maintained." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/RackSec/srslog"] +recommendations = ["github.com/RackSec/srslog"] +reason = "This library's data is not actively maintained." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/ua-parser/uap-go/uaparser"] +recommendations = ["github.com/xavivars/uasurfer"] +reason = "The performance of this library is absolutely abysmal." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."github.com/ugorji/go/codec"] +recommendations = ["encoding/json", "github.com/mailru/easyjson"] +reason = "This library is poorly maintained. We should default to using encoding/json and use easyjson where performance really matters." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."io/ioutil"] + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."gotest.tools/v3/assert"] +recommendations = ["github.com/stretchr/testify/assert"] +reason = "Use github.com/stretchr/testify/assert" + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."golang.org/x/exp/slog"] +recommendations = ["log/slog"] +reason = "Use log/slog" + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."golang.org/x/exp/slices"] +recommendations = ["slices"] +reason = "Use slices" + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."inet.af/netaddr"] +recommendations = ["go4.org/netipx"] +reason = "inet.af/netaddr has been deprecated." + +[[linters-settings.gomodguard.blocked.modules]] +[linters-settings.gomodguard.blocked.modules."k8s.io/utils/strings/slices"] +recommendations = ["slices"] +reason = "Use slices" + +[[linters-settings.gomodguard.blocked.versions]] +[linters-settings.gomodguard.blocked.versions."github.com/jackc/pgconn"] +reason = "Use github.com/jackc/pgx/v5" + +[[linters-settings.gomodguard.blocked.versions]] +[linters-settings.gomodguard.blocked.versions."github.com/jackc/pgtype"] +reason = "Use github.com/jackc/pgx/v5" + +[[linters-settings.gomodguard.blocked.versions]] +[linters-settings.gomodguard.blocked.versions."github.com/jackc/pgx"] +version = "< 5.0.0" +reason = "Use github.com/jackc/pgx/v5" [linters-settings.gosec] - excludes = [ - # G104 - "Audit errors not checked." We use errcheck for this. - "G104", +excludes = [ + # G104 - "Audit errors not checked." We use errcheck for this. + "G104", - # G306 - "Expect WriteFile permissions to be 0600 or less". - "G306", - ] + # G306 - "Expect WriteFile permissions to be 0600 or less". + "G306", + # Prohibits defer (*os.File).Close, which we allow when reading from file. + "G307", +] [linters-settings.govet] - "enable-all" = true +# This seems to be duplicate setting, but enable it for good measure. +check-shadowing = true +"enable-all" = true + +# Although it is very useful in particular cases where we are trying to +# use as little memory as possible, there are even more cases where +# other organizations may make more sense. +disable = ["fieldalignment"] + +[linters-settings.govet.settings.shadow] +strict = true [linters-settings.lll] - line-length = 120 - tab-width = 4 +line-length = 120 +tab-width = 4 [linters-settings.nolintlint] - allow-leading-space = false - allow-unused = false - allow-no-explanation = ["lll", "misspell"] - require-explanation = true - require-specific = true +allow-leading-space = false +allow-unused = false +allow-no-explanation = ["lll", "misspell"] +require-explanation = true +require-specific = true [linters-settings.revive] - ignore-generated-header = true - severity = "warning" +ignore-generated-header = true +severity = "warning" + +# This might be nice but it is so common that it is hard +# to enable. +# [[linters-settings.revive.rules]] +# name = "add-constant" + +# [[linters-settings.revive.rules]] +# name = "argument-limit" + +[[linters-settings.revive.rules]] +name = "atomic" - # This might be nice but it is so common that it is hard - # to enable. - # [[linters-settings.revive.rules]] - # name = "add-constant" +[[linters-settings.revive.rules]] +name = "bare-return" - # [[linters-settings.revive.rules]] - # name = "argument-limit" +[[linters-settings.revive.rules]] +name = "blank-imports" - [[linters-settings.revive.rules]] - name = "atomic" +[[linters-settings.revive.rules]] +name = "bool-literal-in-expr" - [[linters-settings.revive.rules]] - name = "bare-return" +[[linters-settings.revive.rules]] +name = "call-to-gc" - [[linters-settings.revive.rules]] - name = "blank-imports" +# [[linters-settings.revive.rules]] +# name = "cognitive-complexity" - [[linters-settings.revive.rules]] - name = "bool-literal-in-expr" +[[linters-settings.revive.rules]] +name = "comment-spacings" +arguments = ["easyjson", "nolint"] - [[linters-settings.revive.rules]] - name = "call-to-gc" +# Probably a good rule, but we have a lot of names that +# only have case differences. +# [[linters-settings.revive.rules]] +# name = "confusing-naming" - # [[linters-settings.revive.rules]] - # name = "cognitive-complexity" +[[linters-settings.revive.rules]] +name = "confusing-results" - # Probably a good rule, but we have a lot of names that - # only have case differences. - # [[linters-settings.revive.rules]] - # name = "confusing-naming" +[[linters-settings.revive.rules]] +name = "constant-logical-expr" - [[linters-settings.revive.rules]] - name = "confusing-results" +[[linters-settings.revive.rules]] +name = "context-as-argument" - [[linters-settings.revive.rules]] - name = "constant-logical-expr" +[[linters-settings.revive.rules]] +name = "context-keys-type" - [[linters-settings.revive.rules]] - name = "context-as-argument" +# [[linters-settings.revive.rules]] +# name = "cyclomatic" - [[linters-settings.revive.rules]] - name = "context-keys-type" +[[linters-settings.revive.rules]] +name = "datarace" - # [[linters-settings.revive.rules]] - # name = "cyclomatic" +[[linters-settings.revive.rules]] +name = "deep-exit" - [[linters-settings.revive.rules]] - name = "deep-exit" +[[linters-settings.revive.rules]] +name = "defer" - [[linters-settings.revive.rules]] - name = "defer" +[[linters-settings.revive.rules]] +name = "dot-imports" - [[linters-settings.revive.rules]] - name = "dot-imports" +[[linters-settings.revive.rules]] +name = "duplicated-imports" - [[linters-settings.revive.rules]] - name = "duplicated-imports" +[[linters-settings.revive.rules]] +name = "early-return" - [[linters-settings.revive.rules]] - name = "early-return" +[[linters-settings.revive.rules]] +name = "empty-block" - [[linters-settings.revive.rules]] - name = "empty-block" +[[linters-settings.revive.rules]] +name = "empty-lines" - [[linters-settings.revive.rules]] - name = "empty-lines" +[[linters-settings.revive.rules]] +name = "errorf" - [[linters-settings.revive.rules]] - name = "errorf" +[[linters-settings.revive.rules]] +name = "error-naming" - [[linters-settings.revive.rules]] - name = "error-naming" +[[linters-settings.revive.rules]] +name = "error-return" - [[linters-settings.revive.rules]] - name = "error-return" +[[linters-settings.revive.rules]] +name = "error-strings" - [[linters-settings.revive.rules]] - name = "error-strings" +[[linters-settings.revive.rules]] +name = "exported" - [[linters-settings.revive.rules]] - name = "exported" +# [[linters-settings.revive.rules]] +# name = "file-header" - # [[linters-settings.revive.rules]] - # name = "file-header" +# We have a lot of flag parameters. This linter probably makes +# a good point, but we would need some cleanup or a lot of nolints. +# [[linters-settings.revive.rules]] +# name = "flag-parameter" - # We have a lot of flag parameters. This linter probably makes - # a good point, but we would need some cleanup or a lot of nolints. - # [[linters-settings.revive.rules]] - # name = "flag-parameter" +# [[linters-settings.revive.rules]] +# name = "function-result-limit" - # [[linters-settings.revive.rules]] - # name = "function-result-limit" +[[linters-settings.revive.rules]] +name = "get-return" - [[linters-settings.revive.rules]] - name = "get-return" +[[linters-settings.revive.rules]] +name = "identical-branches" - [[linters-settings.revive.rules]] - name = "identical-branches" +[[linters-settings.revive.rules]] +name = "if-return" - [[linters-settings.revive.rules]] - name = "if-return" +[[linters-settings.revive.rules]] +name = "imports-blacklist" - [[linters-settings.revive.rules]] - name = "imports-blacklist" +[[linters-settings.revive.rules]] +name = "import-shadowing" - [[linters-settings.revive.rules]] - name = "import-shadowing" +[[linters-settings.revive.rules]] +name = "increment-decrement" - [[linters-settings.revive.rules]] - name = "increment-decrement" +[[linters-settings.revive.rules]] +name = "indent-error-flow" - [[linters-settings.revive.rules]] - name = "indent-error-flow" +# [[linters-settings.revive.rules]] +# name = "line-length-limit" - # [[linters-settings.revive.rules]] - # name = "line-length-limit" +# [[linters-settings.revive.rules]] +# name = "max-public-structs" - # [[linters-settings.revive.rules]] - # name = "max-public-structs" +[[linters-settings.revive.rules]] +name = "modifies-parameter" - [[linters-settings.revive.rules]] - name = "modifies-parameter" +[[linters-settings.revive.rules]] +name = "modifies-value-receiver" - [[linters-settings.revive.rules]] - name = "modifies-value-receiver" +# We frequently use nested structs, particularly in tests. +# [[linters-settings.revive.rules]] +# name = "nested-structs" - # We frequently use nested structs, particularly in tests. - # [[linters-settings.revive.rules]] - # name = "nested-structs" +[[linters-settings.revive.rules]] +name = "optimize-operands-order" - [[linters-settings.revive.rules]] - name = "optimize-operands-order" +[[linters-settings.revive.rules]] +name = "package-comments" - [[linters-settings.revive.rules]] - name = "package-comments" +[[linters-settings.revive.rules]] +name = "range" - [[linters-settings.revive.rules]] - name = "range" +[[linters-settings.revive.rules]] +name = "range-val-address" - [[linters-settings.revive.rules]] - name = "range-val-address" +[[linters-settings.revive.rules]] +name = "range-val-in-closure" - [[linters-settings.revive.rules]] - name = "range-val-in-closure" +[[linters-settings.revive.rules]] +name = "receiver-naming" - [[linters-settings.revive.rules]] - name = "receiver-naming" +[[linters-settings.revive.rules]] +name = "redefines-builtin-id" - [[linters-settings.revive.rules]] - name = "redefines-builtin-id" +[[linters-settings.revive.rules]] +name = "string-of-int" - [[linters-settings.revive.rules]] - name = "string-of-int" +[[linters-settings.revive.rules]] +name = "struct-tag" - [[linters-settings.revive.rules]] - name = "struct-tag" +[[linters-settings.revive.rules]] +name = "superfluous-else" - [[linters-settings.revive.rules]] - name = "superfluous-else" +[[linters-settings.revive.rules]] +name = "time-equal" - [[linters-settings.revive.rules]] - name = "time-naming" +[[linters-settings.revive.rules]] +name = "time-naming" - [[linters-settings.revive.rules]] - name = "unconditional-recursion" +[[linters-settings.revive.rules]] +name = "unconditional-recursion" - [[linters-settings.revive.rules]] - name = "unexported-naming" +[[linters-settings.revive.rules]] +name = "unexported-naming" - [[linters-settings.revive.rules]] - name = "unexported-return" +[[linters-settings.revive.rules]] +name = "unexported-return" - # This is covered elsewhere and we want to ignore some - # functions such as fmt.Fprintf. - # [[linters-settings.revive.rules]] - # name = "unhandled-error" +# This is covered elsewhere and we want to ignore some +# functions such as fmt.Fprintf. +# [[linters-settings.revive.rules]] +# name = "unhandled-error" - [[linters-settings.revive.rules]] - name = "unnecessary-stmt" +[[linters-settings.revive.rules]] +name = "unnecessary-stmt" - [[linters-settings.revive.rules]] - name = "unreachable-code" +[[linters-settings.revive.rules]] +name = "unreachable-code" - [[linters-settings.revive.rules]] - name = "unused-parameter" +[[linters-settings.revive.rules]] +name = "unused-parameter" - # We generally have unused receivers in tests for meeting the - # requirements of an interface. - # [[linters-settings.revive.rules]] - # name = "unused-receiver" +# We generally have unused receivers in tests for meeting the +# requirements of an interface. +# [[linters-settings.revive.rules]] +# name = "unused-receiver" - # This probably makes sense after we upgrade to 1.18 - # [[linters-settings.revive.rules]] - # name = "use-any" +[[linters-settings.revive.rules]] +name = "use-any" - [[linters-settings.revive.rules]] - name = "useless-break" +[[linters-settings.revive.rules]] +name = "useless-break" - [[linters-settings.revive.rules]] - name = "var-declaration" +[[linters-settings.revive.rules]] +name = "var-declaration" - [[linters-settings.revive.rules]] - name = "var-naming" +[[linters-settings.revive.rules]] +name = "var-naming" - [[linters-settings.revive.rules]] - name = "waitgroup-by-value" +[[linters-settings.revive.rules]] +name = "waitgroup-by-value" [linters-settings.unparam] - check-exported = true - -[linters-settings.wrapcheck] - "ignoreSigs" = [ - ".Errorf(", - "errgroup.NewMultiError(", - "mmerrors.New(", - ".Wait(", - ".WithStack(", - ".Wrap(", - ".Wrapf(", - "v4.Retry(", - "v4.RetryNotify(", - ] +check-exported = true [issues] exclude-use-default = false - [[issues.exclude-rules]] - linters = [ - "gocritic" - ] - # For some reason the imports stuff in ruleguard doesn't work in golangci-lint. - # Perhaps it has an outdated version or something - path = "_test.go" - text = "ruleguard: Prefer the alternative Context method instead" - - [[issues.exclude-rules]] - linters = [ - "gocritic" - ] - ## The nolintlint linter behaves oddly with ruleguard rules - source = "// *no-ruleguard" - - [[issues.exclude-rules]] - linters = [ - "govet" - ] - # we want to enable almost all govet rules. It is easier to just filter out - # the ones we don't want: - # - # * fieldalignment - way too noisy. Although it is very useful in particular - # cases where we are trying to use as little memory as possible, having - # it go off on every struct isn't helpful. - # * shadow - although often useful, it complains about _many_ err - # shadowing assignments and some others where shadowing is clear. - text = "^(fieldalignment|shadow)" - - [[issues.exclude-rules]] - linters = [ - "govet" - ] - text = "shadow: declaration of \"err\" shadows declaration" - - [[issues.exclude-rules]] - linters = [ +# This goes off for MD5 usage, which we use heavily +[[issues.exclude-rules]] +text = "weak cryptographic primitive" +linters = ["gosec"] + +[[issues.exclude-rules]] +linters = [ + "bodyclose", +] +# This rule doesn't really make sense for tests where we don't have an open +# connection and we might be passing around the response for other reasons. +path = "_test.go" + +[[issues.exclude-rules]] +linters = [ + "forbidigo", +] +# This refers to a minFraud field, not the MaxMind Account ID +source = "AccountUserID|Account\\.UserID" + +# we include both a source and text exclusion as the source exclusion +# misses matches where forbidigo reports the error on the first line +# of a chunk of a function call even though the use is on a later line. +[[issues.exclude-rules]] +linters = [ + "forbidigo", +] +text = "AccountUserID|Account\\.UserID" + +[[issues.exclude-rules]] +linters = [ + "gocritic", +] +# For some reason the imports stuff in ruleguard doesn't work in golangci-lint. +# Perhaps it has an outdated version or something +path = "_test.go" +text = "ruleguard: Prefer the alternative Context method instead" + +[[issues.exclude-rules]] +linters = [ + "gocritic", +] +# The nolintlint linter behaves oddly with ruleguard rules +source = "// *no-ruleguard" + +[[issues.exclude-rules]] +linters = [ + "govet", +] +# These are usually fine to shadow and not allowing shadowing for them can +# make the code unnecessarily verbose. +text = 'shadow: declaration of "(ctx|err|ok)" shadows declaration' + +[[issues.exclude-rules]] +linters = [ "contextcheck", + # With recent changes to the linter, there were a lot of failures in + # the tests and it wasn't clear to me that fixing them would actually + # improve the readability. + "goconst", "nilerr", "wrapcheck", - ] - path = "_test.go" +] +path = "_test.go" + +[[issues.exclude-rules]] +linters = [ + "stylecheck", +] +# ST1016 - methods on the same type should have the same receiver name. +# easyjson doesn't interact well with this. +text = "ST1016" + +[[issues.exclude-rules]] +linters = [ + "staticcheck", +] +# SA5008: unknown JSON option "intern" - easyjson specific option. +text = 'SA5008: unknown JSON option "intern"' + +[[issues.exclude-rules]] +linters = [ + "wrapcheck", +] +path = "_easyjson.go" - [[issues.exclude-rules]] - linters = [ +[[issues.exclude-rules]] +linters = [ "gocritic", - ] - source = "Chmod|WriteFile" - text = "octalLiteral" +] +source = "Chmod|WriteFile" +text = "octalLiteral" diff --git a/vendor/github.com/maxmind/mmdbwriter/data_key.go b/vendor/github.com/maxmind/mmdbwriter/data_key.go index 20d675ac..a14bc42e 100644 --- a/vendor/github.com/maxmind/mmdbwriter/data_key.go +++ b/vendor/github.com/maxmind/mmdbwriter/data_key.go @@ -8,11 +8,30 @@ import ( "github.com/maxmind/mmdbwriter/mmdbtype" ) +// KeyGenerator generates a unique key for record values being inserted into the +// Tree. This is used for deduplicating the values in memory. The default +// KeyGenerator will serialize and hash the whole datastructure. This handles +// the general case well but may be inefficient given the particulars of the +// data. +// +// Please be certain that any key you generate is unique. If there is a +// collision with two different values having the same key, one of the +// values will be overwritten. +// +// The returned byte slice is not stored. You may use the same backing +// array between calls. +type KeyGenerator interface { + Key(mmdbtype.DataType) ([]byte, error) +} + +var _ KeyGenerator = &keyWriter{} + // keyWriter is similar to dataWriter but it will never use pointers. This // will produce a unique key for the type. type keyWriter struct { *bytes.Buffer sha256 hash.Hash + key [sha256.Size]byte } func newKeyWriter() *keyWriter { @@ -21,17 +40,17 @@ func newKeyWriter() *keyWriter { // This is just a quick hack. I am sure there is // something better. -func (kw *keyWriter) key(t mmdbtype.DataType) ([]byte, error) { +func (kw *keyWriter) Key(v mmdbtype.DataType) ([]byte, error) { kw.Truncate(0) kw.sha256.Reset() - _, err := t.WriteTo(kw) + _, err := v.WriteTo(kw) if err != nil { return nil, err } if _, err := kw.WriteTo(kw.sha256); err != nil { return nil, err } - return kw.sha256.Sum(nil), nil + return kw.sha256.Sum(kw.key[:0]), nil } func (kw *keyWriter) WriteOrWritePointer(t mmdbtype.DataType) (int64, error) { diff --git a/vendor/github.com/maxmind/mmdbwriter/data_map.go b/vendor/github.com/maxmind/mmdbwriter/data_map.go index c1b52fd3..9119bccb 100644 --- a/vendor/github.com/maxmind/mmdbwriter/data_map.go +++ b/vendor/github.com/maxmind/mmdbwriter/data_map.go @@ -20,13 +20,13 @@ type dataMapValue struct { // memory usage using keys generated by keyWriter. type dataMap struct { data map[dataMapKey]*dataMapValue - keyWriter *keyWriter + keyWriter KeyGenerator } -func newDataMap() *dataMap { +func newDataMap(keyWriter KeyGenerator) *dataMap { return &dataMap{ data: map[dataMapKey]*dataMapValue{}, - keyWriter: newKeyWriter(), + keyWriter: keyWriter, } } @@ -34,7 +34,7 @@ func newDataMap() *dataMap { // If the value is already in the dataMap, the reference count for it is // incremented. func (dm *dataMap) store(v mmdbtype.DataType) (*dataMapValue, error) { - key, err := dm.keyWriter.key(v) + key, err := dm.keyWriter.Key(v) if err != nil { return nil, err } @@ -57,6 +57,11 @@ func (dm *dataMap) store(v mmdbtype.DataType) (*dataMapValue, error) { // remove removes a reference to the value. If the reference count // drops to zero, the value is removed from the dataMap. func (dm *dataMap) remove(v *dataMapValue) { + // This is here mostly so that we don't have to guard against it + // elsewhere. + if v == nil { + return + } v.refCount-- if v.refCount == 0 { diff --git a/vendor/github.com/maxmind/mmdbwriter/data_section.go b/vendor/github.com/maxmind/mmdbwriter/data_section.go index 3eaf9070..dba44451 100644 --- a/vendor/github.com/maxmind/mmdbwriter/data_section.go +++ b/vendor/github.com/maxmind/mmdbwriter/data_section.go @@ -52,7 +52,7 @@ func (dw *dataWriter) maybeWrite(value *dataMapValue) (int, error) { } func (dw *dataWriter) WriteOrWritePointer(t mmdbtype.DataType) (int64, error) { - keyBytes, err := dw.keyWriter.key(t) + keyBytes, err := dw.keyWriter.Key(t) if err != nil { return 0, err } diff --git a/vendor/github.com/maxmind/mmdbwriter/errors.go b/vendor/github.com/maxmind/mmdbwriter/errors.go new file mode 100644 index 00000000..bffec803 --- /dev/null +++ b/vendor/github.com/maxmind/mmdbwriter/errors.go @@ -0,0 +1,124 @@ +package mmdbwriter + +import ( + "errors" + "fmt" + "net" + "net/netip" +) + +// AliasedNetworkError is returned when inserting a aliased network into +// a Tree where DisableIPv4Aliasing in Options is false. +type AliasedNetworkError struct { + // AliasedNetwork is the aliased network being inserted into. + AliasedNetwork netip.Prefix + // InsertedNetwork is the network being inserted into the Tree. + InsertedNetwork netip.Prefix +} + +func newAliasedNetworkError(netIP net.IP, curPrefixLen, recPrefixLen int) error { + anErr := &AliasedNetworkError{} + ip, ok := netip.AddrFromSlice(netIP) + if !ok { + return errors.Join( + fmt.Errorf("creating netip.Addr from %s", netIP), + anErr, + ) + } + var err error + // We are using netip here despite using net.IP/net.IPNet internally as + // it seems quite likely that we will switch to netip throughout. + anErr.InsertedNetwork, err = ip.Prefix(recPrefixLen) + if err != nil { + return errors.Join( + fmt.Errorf( + "creating prefix from addr %s and prefix length %d: %w", + ip, + recPrefixLen, + err, + ), + anErr, + ) + } + + anErr.AliasedNetwork, err = ip.Prefix(curPrefixLen) + if err != nil { + return errors.Join( + fmt.Errorf( + "creating prefix from addr %s and prefix length %d: %w", + ip, + curPrefixLen, + err, + ), + anErr, + ) + } + return anErr +} + +func (r *AliasedNetworkError) Error() string { + return fmt.Sprintf( + "attempt to insert %s into %s, which is an aliased network", + r.InsertedNetwork, + r.AliasedNetwork, + ) +} + +// ReservedNetworkError is returned when inserting a reserved network into +// a Tree where IncludeReservedNetworks in Options is false. +type ReservedNetworkError struct { + // InsertedNetwork is the network being inserted into the Tree. + InsertedNetwork netip.Prefix + // ReservedNetwork is the reserved network being inserted into. + ReservedNetwork netip.Prefix +} + +var _ error = &ReservedNetworkError{} + +func newReservedNetworkError(netIP net.IP, curPrefixLen, recPrefixLen int) error { + rnErr := &ReservedNetworkError{} + ip, ok := netip.AddrFromSlice(netIP) + if !ok { + return errors.Join( + fmt.Errorf("creating netip.Addr from %s", netIP), + rnErr, + ) + } + var err error + // We are using netip here despite using net.IP/net.IPNet internally as + // it seems quite likely that we will switch to netip throughout. + rnErr.InsertedNetwork, err = ip.Prefix(recPrefixLen) + if err != nil { + return errors.Join( + fmt.Errorf( + "creating prefix from addr %s and prefix length %d: %w", + ip, + recPrefixLen, + err, + ), + rnErr, + ) + } + + rnErr.ReservedNetwork, err = ip.Prefix(curPrefixLen) + if err != nil { + return errors.Join( + fmt.Errorf( + "creating prefix from addr %s and prefix length %d: %w", + ip, + curPrefixLen, + err, + ), + rnErr, + ) + } + return rnErr +} + +func (r *ReservedNetworkError) Error() string { + return fmt.Sprintf( + "attempt to insert %s into %s, which is a reserved network", + r.InsertedNetwork, + r.ReservedNetwork, + ) +} diff --git a/vendor/github.com/maxmind/mmdbwriter/mmdbtype/types.go b/vendor/github.com/maxmind/mmdbwriter/mmdbtype/types.go index d61afd18..d14ae6d0 100644 --- a/vendor/github.com/maxmind/mmdbwriter/mmdbtype/types.go +++ b/vendor/github.com/maxmind/mmdbwriter/mmdbtype/types.go @@ -2,12 +2,16 @@ package mmdbtype import ( + "bytes" "encoding/binary" "fmt" "io" "math/big" "math/bits" - "sort" + "reflect" + + // TODO: Once the min Go version is 1.21, switch this to "slices". + "golang.org/x/exp/slices" ) type typeNum byte @@ -43,6 +47,7 @@ type writer interface { // DataType represents a MaxMind DB data type. type DataType interface { Copy() DataType + Equal(DataType) bool size() int typeNum() typeNum WriteTo(writer) (int64, error) @@ -51,9 +56,17 @@ type DataType interface { // Bool is the MaxMind DB boolean type. type Bool bool +var _ DataType = (*Bool)(nil) + // Copy the value. func (t Bool) Copy() DataType { return t } +// Equal checks for equality. +func (t Bool) Equal(other DataType) bool { + otherT, ok := other.(Bool) + return ok && t == otherT +} + func (t Bool) size() int { if t { return 1 @@ -73,6 +86,8 @@ func (t Bool) WriteTo(w writer) (int64, error) { // Bytes is the MaxMind DB bytes type. type Bytes []byte +var _ DataType = Bytes(nil) + // Copy the value. func (t Bytes) Copy() DataType { nv := make(Bytes, len(t)) @@ -80,6 +95,16 @@ func (t Bytes) Copy() DataType { return nv } +// Equal checks for equality. +func (t Bytes) Equal(other DataType) bool { + otherT, ok := other.(Bytes) + if !ok { + return false + } + + return bytes.Equal(t, otherT) +} + func (t Bytes) size() int { return len(t) } @@ -106,9 +131,17 @@ func (t Bytes) WriteTo(w writer) (int64, error) { // Float32 is the MaxMind DB float type. type Float32 float32 +var _ DataType = (*Float32)(nil) + // Copy the value. func (t Float32) Copy() DataType { return t } +// Equal checks for equality. +func (t Float32) Equal(other DataType) bool { + otherT, ok := other.(Float32) + return ok && t == otherT +} + func (t Float32) size() int { return 4 } @@ -134,9 +167,17 @@ func (t Float32) WriteTo(w writer) (int64, error) { // Float64 is the MaxMind DB double type. type Float64 float64 +var _ DataType = (*Float64)(nil) + // Copy the value. func (t Float64) Copy() DataType { return t } +// Equal checks for equality. +func (t Float64) Equal(other DataType) bool { + otherT, ok := other.(Float64) + return ok && t == otherT +} + func (t Float64) size() int { return 8 } @@ -162,9 +203,17 @@ func (t Float64) WriteTo(w writer) (int64, error) { // Int32 is the MaxMind DB signed 32-bit integer type. type Int32 int32 +var _ DataType = (*Int32)(nil) + // Copy the value. func (t Int32) Copy() DataType { return t } +// Equal checks for equality. +func (t Int32) Equal(other DataType) bool { + otherT, ok := other.(Int32) + return ok && t == otherT +} + func (t Int32) size() int { return 4 - bits.LeadingZeros32(uint32(t))/8 } @@ -194,6 +243,8 @@ func (t Int32) WriteTo(w writer) (int64, error) { // Map is the MaxMind DB map type. type Map map[String]DataType +var _ DataType = Map(nil) + // Copy makes a deep copy of the Map. func (t Map) Copy() DataType { newMap := make(Map, len(t)) @@ -203,6 +254,29 @@ func (t Map) Copy() DataType { return newMap } +// Equal checks for equality. +func (t Map) Equal(other DataType) bool { + otherT, ok := other.(Map) + if !ok { + return false + } + + if len(t) != len(otherT) { + return false + } + + if reflect.ValueOf(t).Pointer() == reflect.ValueOf(otherT).Pointer() { + return true + } + + for k, v := range t { + if ov, ok := otherT[k]; !ok || !v.Equal(ov) { + return false + } + } + return true +} + func (t Map) size() int { return len(t) } @@ -226,7 +300,7 @@ func (t Map) WriteTo(w writer) (int64, error) { for k := range t { keys = append(keys, string(k)) } - sort.Strings(keys) + slices.Sort(keys) for _, ks := range keys { k := String(ks) @@ -249,9 +323,17 @@ func (t Map) WriteTo(w writer) (int64, error) { // mmdbwriter.Tree. Doing so may result in a corrupt database. type Pointer uint32 +var _ DataType = (*Pointer)(nil) + // Copy the value. func (t Pointer) Copy() DataType { return t } +// Equal checks for equality. +func (t Pointer) Equal(other DataType) bool { + otherT, ok := other.(Pointer) + return ok && t == otherT +} + const ( pointerMaxSize0 = 1 << 11 pointerMaxSize1 = pointerMaxSize0 + (1 << 19) @@ -354,6 +436,8 @@ func (t Pointer) WriteTo(w writer) (int64, error) { // Slice is the MaxMind DB array type. type Slice []DataType +var _ DataType = Slice(nil) + // Copy makes a deep copy of the Slice. func (t Slice) Copy() DataType { newSlice := make(Slice, len(t)) @@ -363,6 +447,29 @@ func (t Slice) Copy() DataType { return newSlice } +// Equal checks for equality. +func (t Slice) Equal(other DataType) bool { + otherT, ok := other.(Slice) + if !ok { + return false + } + + if len(t) != len(otherT) { + return false + } + + if reflect.ValueOf(t).Pointer() == reflect.ValueOf(otherT).Pointer() { + return true + } + + for i, v := range t { + if !otherT[i].Equal(v) { + return false + } + } + return true +} + func (t Slice) size() int { return len(t) } @@ -391,9 +498,17 @@ func (t Slice) WriteTo(w writer) (int64, error) { // String is the MaxMind DB string type. type String string +var _ DataType = (*String)(nil) + // Copy the value. func (t String) Copy() DataType { return t } +// Equal checks for equality. +func (t String) Equal(other DataType) bool { + otherT, ok := other.(String) + return ok && t == otherT +} + func (t String) size() int { return len(t) } @@ -420,9 +535,17 @@ func (t String) WriteTo(w writer) (int64, error) { // Uint16 is the MaxMind DB unsigned 16-bit integer type. type Uint16 uint16 +var _ DataType = (*Uint16)(nil) + // Copy the value. func (t Uint16) Copy() DataType { return t } +// Equal checks for equality. +func (t Uint16) Equal(other DataType) bool { + otherT, ok := other.(Uint16) + return ok && t == otherT +} + func (t Uint16) size() int { return 2 - bits.LeadingZeros16(uint16(t))/8 } @@ -452,6 +575,14 @@ func (t Uint16) WriteTo(w writer) (int64, error) { // Uint32 is the MaxMind DB unsigned 32-bit integer type. type Uint32 uint32 +var _ DataType = (*Uint32)(nil) + +// Equal checks for equality. +func (t Uint32) Equal(other DataType) bool { + otherT, ok := other.(Uint32) + return ok && t == otherT +} + // Copy the value. func (t Uint32) Copy() DataType { return t } @@ -484,9 +615,17 @@ func (t Uint32) WriteTo(w writer) (int64, error) { // Uint64 is the MaxMind DB unsigned 64-bit integer type. type Uint64 uint64 +var _ DataType = (*Uint64)(nil) + // Copy the value. func (t Uint64) Copy() DataType { return t } +// Equal checks for equality. +func (t Uint64) Equal(other DataType) bool { + otherT, ok := other.(Uint64) + return ok && t == otherT +} + func (t Uint64) size() int { return 8 - bits.LeadingZeros64(uint64(t))/8 } @@ -517,6 +656,8 @@ func (t Uint64) WriteTo(w writer) (int64, error) { // Uint128 is the MaxMind DB unsigned 128-bit integer type. type Uint128 big.Int +var _ DataType = (*Uint128)(nil) + // Copy make a deep copy of the Uint128. func (t *Uint128) Copy() DataType { nv := big.Int{} @@ -525,6 +666,12 @@ func (t *Uint128) Copy() DataType { return &uv } +// Equal checks for equality. +func (t *Uint128) Equal(other DataType) bool { + otherT, ok := other.(*Uint128) + return ok && (*big.Int)(t).Cmp((*big.Int)(otherT)) == 0 +} + func (t *Uint128) size() int { // We add 7 here as we want the ceiling of the division operation rather // than the floor. @@ -560,16 +707,16 @@ const ( func writeCtrlByte(w writer, t DataType) (int64, error) { size := t.size() - typeNum := t.typeNum() + typeN := t.typeNum() var firstByte byte var secondByte byte - if typeNum < 8 { - firstByte = byte(typeNum << 5) + if typeN < 8 { + firstByte = byte(typeN << 5) } else { firstByte = byte(typeNumExtended << 5) - secondByte = byte(typeNum - 7) + secondByte = byte(typeN - 7) } leftOver := 0 @@ -577,15 +724,15 @@ func writeCtrlByte(w writer, t DataType) (int64, error) { switch { case size < firstSize: firstByte |= byte(size) - case size <= secondSize: + case size < secondSize: firstByte |= 29 leftOver = size - firstSize leftOverSize = 1 - case size <= thirdSize: + case size < thirdSize: firstByte |= 30 leftOver = size - secondSize leftOverSize = 2 - case size <= maxSize: + case size < maxSize: firstByte |= 31 leftOver = size - thirdSize leftOverSize = 3 @@ -593,7 +740,7 @@ func writeCtrlByte(w writer, t DataType) (int64, error) { return 0, fmt.Errorf( "cannot store %d bytes; max size is %d", size, - maxSize, + maxSize-1, ) } @@ -601,7 +748,7 @@ func writeCtrlByte(w writer, t DataType) (int64, error) { if err != nil { return 0, fmt.Errorf( "writing first ctrl byte (type: %d, size: %d): %w", - typeNum, + typeN, size, err, ) @@ -613,7 +760,7 @@ func writeCtrlByte(w writer, t DataType) (int64, error) { if err != nil { return numBytes, fmt.Errorf( "writing second ctrl byte (type: %d, size: %d): %w", - typeNum, + typeN, size, err, ) @@ -627,7 +774,7 @@ func writeCtrlByte(w writer, t DataType) (int64, error) { if err != nil { return numBytes, fmt.Errorf( "writing remaining ctrl bytes (type: %d, size: %d, value: %d): %w", - typeNum, + typeN, size, v, err, diff --git a/vendor/github.com/maxmind/mmdbwriter/node.go b/vendor/github.com/maxmind/mmdbwriter/node.go index dcd7d6d1..49a19ec8 100644 --- a/vendor/github.com/maxmind/mmdbwriter/node.go +++ b/vendor/github.com/maxmind/mmdbwriter/node.go @@ -66,31 +66,34 @@ func (r *record) insert( newDepth int, ) error { switch r.recordType { - case recordTypeNode, recordTypeFixedNode: + case recordTypeNode: + err := r.node.insert(iRec, newDepth) + if err != nil { + return err + } + return r.maybeMergeChildren(iRec) + case recordTypeFixedNode: + return r.node.insert(iRec, newDepth) case recordTypeEmpty, recordTypeData: if newDepth >= iRec.prefixLen { r.node = iRec.insertedNode r.recordType = iRec.recordType if iRec.recordType == recordTypeData { - var data mmdbtype.DataType + var oldData mmdbtype.DataType if r.value != nil { - data = r.value.data - - // Potentially we could avoid this if the - // new value is the same, but it would likely - // not save us much and the code would be a - // bit more complicated. - iRec.dataMap.remove(r.value) + oldData = r.value.data } - value, err := iRec.inserter(data) + newData, err := iRec.inserter(oldData) if err != nil { return err } - if value == nil { + if newData == nil { + iRec.dataMap.remove(r.value) r.recordType = recordTypeEmpty r.value = nil - } else { - value, err := iRec.dataMap.store(value) + } else if oldData == nil || !oldData.Equal(newData) { + iRec.dataMap.remove(r.value) + value, err := iRec.dataMap.store(newData) if err != nil { return err } @@ -107,13 +110,14 @@ func (r *record) insert( r.node = &node{children: [2]record{*r, *r}} r.value = nil r.recordType = recordTypeNode + err := r.node.insert(iRec, newDepth) + if err != nil { + return err + } + return r.maybeMergeChildren(iRec) case recordTypeReserved: if iRec.prefixLen >= newDepth { - return fmt.Errorf( - "attempt to insert %s/%d, which is in a reserved network", - iRec.ip, - iRec.prefixLen, - ) + return newReservedNetworkError(iRec.ip, newDepth, iRec.prefixLen) } // If we are inserting a network that contains a reserved network, // we silently remove the reserved network. @@ -125,16 +129,40 @@ func (r *record) insert( return nil } // attempting to insert _into_ an aliased network - return fmt.Errorf( - "attempt to insert %s/%d, which is in an aliased network", - iRec.ip, - iRec.prefixLen, - ) + return newAliasedNetworkError(iRec.ip, newDepth, iRec.prefixLen) default: return fmt.Errorf("inserting into record type %d is not implemented", r.recordType) } +} - return r.node.insert(iRec, newDepth) +func (r *record) maybeMergeChildren(iRec insertRecord) error { + // Check to see if the children are the same and can be merged. + child0 := r.node.children[0] + child1 := r.node.children[1] + if child0.recordType != child1.recordType { + return nil + } + switch child0.recordType { + // Nodes can't be merged + case recordTypeFixedNode, recordTypeNode: + return nil + case recordTypeEmpty, recordTypeReserved: + r.recordType = child0.recordType + r.node = nil + return nil + case recordTypeData: + if child0.value.key != child1.value.key { + return nil + } + // Children have same data and can be merged + r.recordType = recordTypeData + r.value = child0.value + iRec.dataMap.remove(child1.value) + r.node = nil + return nil + default: + return fmt.Errorf("merging record type %d is not implemented", child0.recordType) + } } func (n *node) get( @@ -153,42 +181,22 @@ func (n *node) get( } } -// finalize prunes unnecessary nodes (e.g., where the two records are the same) and -// sets the node number for the node. It returns a record pointer that is nil if -// the node is not mergeable or the value of the merged record if it can be merged. -// The second return value is the current node count, including the subtree. -func (n *node) finalize(currentNum int) (*record, int) { +// finalize sets the node number for the node. It returns the current node +// count, including the subtree. +func (n *node) finalize(currentNum int) int { n.nodeNum = currentNum currentNum++ for i := 0; i < 2; i++ { switch n.children[i].recordType { - case recordTypeFixedNode: - // We don't consider merging for fixed nodes - _, currentNum = n.children[i].node.finalize(currentNum) - case recordTypeNode: - record, newCurrentNum := n.children[i].node.finalize(currentNum) - if record == nil { - // nothing to merge. Use current number from child. - currentNum = newCurrentNum - } else { - n.children[i] = *record - } + case recordTypeFixedNode, + recordTypeNode: + currentNum = n.children[i].node.finalize(currentNum) default: } } - if n.children[0].recordType == n.children[1].recordType && - (n.children[0].recordType == recordTypeEmpty || - (n.children[0].recordType == recordTypeData && - n.children[0].value.key == n.children[1].value.key)) { - return &record{ - recordType: n.children[0].recordType, - value: n.children[0].value, - }, currentNum - } - - return nil, currentNum + return currentNum } func bitAt(ip net.IP, depth int) byte { diff --git a/vendor/github.com/maxmind/mmdbwriter/tree.go b/vendor/github.com/maxmind/mmdbwriter/tree.go index ba67b1df..36d087f2 100644 --- a/vendor/github.com/maxmind/mmdbwriter/tree.go +++ b/vendor/github.com/maxmind/mmdbwriter/tree.go @@ -13,7 +13,7 @@ import ( "github.com/maxmind/mmdbwriter/inserter" "github.com/maxmind/mmdbwriter/mmdbtype" "github.com/oschwald/maxminddb-golang" - "inet.af/netaddr" + "go4.org/netipx" ) var ( @@ -78,6 +78,17 @@ type Options struct { // to `inserter.ReplaceWith`, which replaces any conflicting old value // entirely with the new. Inserter inserter.FuncGenerator + + // KeyGenerator is used to generate unique keys for the top-level record + // values inserted into the database. This is used to deduplicate data + // in memory as the tree is being created. The KeyGenerator must + // generate a unique key for the value. If two different values have + // the same key, only one will be used. + // + // The default key generator serializes the value and generates a + // SHA-256 hash from it. Although this is relatively safe, it can be + // resource intensive for large data structures. + KeyGenerator KeyGenerator } // Tree represents an MaxMind DB search tree. @@ -101,7 +112,6 @@ type Tree struct { func New(opts Options) (*Tree, error) { tree := &Tree{ buildEpoch: time.Now().Unix(), - dataMap: newDataMap(), databaseType: opts.DatabaseType, description: map[string]string{}, disableMetadataPointers: opts.DisableMetadataPointers, @@ -123,6 +133,12 @@ func New(opts Options) (*Tree, error) { tree.ipVersion = opts.IPVersion } + if opts.KeyGenerator == nil { + tree.dataMap = newDataMap(newKeyWriter()) + } else { + tree.dataMap = newDataMap(opts.KeyGenerator) + } + if opts.Languages != nil { tree.languages = opts.Languages } @@ -310,22 +326,22 @@ func (t *Tree) insertRange( inserterFunc inserter.Func, node *node, ) error { - _start, ok := netaddr.FromStdIP(start) + startNetIP, ok := netipx.FromStdIP(start) if !ok { return errors.New("start IP is invalid") } - _end, ok := netaddr.FromStdIP(end) + endNetIP, ok := netipx.FromStdIP(end) if !ok { return errors.New("end IP is invalid") } - r := netaddr.IPRangeFrom(_start, _end) + r := netipx.IPRangeFrom(startNetIP, endNetIP) if !r.IsValid() { return errors.New("start & end IPs did not give valid range") } subnets := r.Prefixes() for _, subnet := range subnets { - if err := t.insert(subnet.IPNet(), recordType, inserterFunc, node); err != nil { + if err := t.insert(netipx.PrefixIPNet(subnet), recordType, inserterFunc, node); err != nil { return err } } @@ -339,6 +355,7 @@ func (t *Tree) insertStringNetwork( inserterFunc inserter.Func, node *node, ) error { + //nolint:forbidigo // code predates netip _, ipnet, err := net.ParseCIDR(network) if err != nil { return fmt.Errorf("parsing network (%s): %w", network, err) @@ -353,6 +370,7 @@ var ipv4AliasNetworks = []string{ } func (t *Tree) insertIPv4Aliases() error { + //nolint:forbidigo // code predates netip _, ipv4Root, err := net.ParseCIDR("::/96") if err != nil { return fmt.Errorf("parsing IPv4 root: %w", err) @@ -406,18 +424,17 @@ func (t *Tree) Get(ip net.IP) (*net.IPNet, mmdbtype.DataType) { // the MaxMind DB format has the record for 1.1.1.1 at ::1.1.1.1. if ipv4 := ip.To4(); ipv4 != nil { lookupIP = ipV4ToV6(ipv4) + + // This simplifies the logic around creating the IPNet. If we didn't + // do this, we would need to specifically adjust the prefix length + // when creating the mask and we would also need to worry about + // what to do if there isn't an IPv4 tree. + ip = ip.To16() } } prefixLen, r := t.root.get(lookupIP, 0) - // This is so that if you look up an IPv4 address in a database that has - // an IPv4 subtree, you will get back an IPv4 network. This matches what - // github.com/oschwald/maxminddb-golang does. - if prefixLen >= 96 && len(ip) == 4 { - prefixLen -= 96 - } - mask := net.CIDRMask(prefixLen, t.treeDepth) var value mmdbtype.DataType @@ -433,7 +450,7 @@ func (t *Tree) Get(ip net.IP) (*net.IPNet, mmdbtype.DataType) { // finalize prepares the tree for writing. It is not threadsafe. func (t *Tree) finalize() { - _, t.nodeCount = t.root.finalize(0) + t.nodeCount = t.root.finalize(0) } // WriteTo writes the tree to the provided Writer. diff --git a/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml b/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml index b4f7e6a1..0950c1c5 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml +++ b/vendor/github.com/oschwald/maxminddb-golang/.golangci.toml @@ -1,26 +1,26 @@ [run] deadline = "10m" - tests = true [linters] disable-all = true enable = [ + "asasalint", "asciicheck", "bidichk", "bodyclose", "containedctx", "contextcheck", - "deadcode", "depguard", + "dupword", "durationcheck", "errcheck", "errchkjson", "errname", "errorlint", + # "exhaustive", "exportloopref", "forbidigo", - #"forcetypeassert", "goconst", "gocyclo", "gocritic", @@ -46,7 +46,6 @@ "rowserrcheck", "sqlclosecheck", "staticcheck", - "structcheck", "stylecheck", "tenv", "tparallel", @@ -54,40 +53,17 @@ "unconvert", "unparam", "unused", - "varcheck", + "usestdlibvars", "vetshadow", "wastedassign", ] -# Please note that we only use depguard for stdlib as gomodguard only -# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12 -[linters-settings.depguard] - list-type = "blacklist" - include-go-root = true - packages = [ - # ioutil is deprecated. The functions have been moved elsewhere: - # https://golang.org/doc/go1.16#ioutil - "io/ioutil", - ] +[[linters-settings.depguard.rules.main.deny]] +pkg = "io/ioutil" +desc = "Deprecated. Functions have been moved elsewhere." [linters-settings.errcheck] - # Don't allow setting of error to the blank identifier. If there is a legtimate - # reason, there should be a nolint with an explanation. check-blank = true - - exclude-functions = [ - # If we are rolling back a transaction, we are often already in an error - # state. - '(*database/sql.Tx).Rollback', - - # It is reasonable to ignore errors if Cleanup fails in most cases. - '(*github.com/google/renameio/v2.PendingFile).Cleanup', - - # We often don't care if removing a file failed (e.g., it doesn't exist) - 'os.Remove', - 'os.RemoveAll', - ] - # Ignoring Close so that we don't have to have a bunch of # `defer func() { _ = r.Close() }()` constructs when we # don't actually care about the error. @@ -104,8 +80,10 @@ [linters-settings.forbidigo] # Forbid the following identifiers forbid = [ - "^minFraud*", - "^maxMind*", + "Geoip", # use "GeoIP" + "^geoIP", # use "geoip" + "Maxmind", # use "MaxMind" + "^maxMind", # use "maxmind" ] [linters-settings.gocritic] @@ -129,8 +107,7 @@ "commentedOutImport", "commentFormatting", "defaultCaseOrder", - # Revive's defer rule already captures this. This caught no extra cases. - # "deferInLoop", + "deferInLoop", "deferUnlambda", "deprecatedComment", "docStub", @@ -149,17 +126,16 @@ "exitAfterDefer", "exposedSyncMutex", "externalErrorReassign", - # Given that all of our code runs on Linux and the / separate should - # work fine, this seems less important. - # "filepathJoin", + "filepathJoin", "flagDeref", "flagName", "hexLiteral", + "httpNoBody", + "hugeParam", "ifElseChain", "importShadow", "indexAlloc", "initClause", - "ioutilDeprecated", "mapKey", "methodExprCall", "nestingReduce", @@ -179,22 +155,20 @@ "redundantSprint", "regexpMust", "regexpPattern", - # This might be good, but I don't think we want to encourage - # significant changes to regexes as we port stuff from Perl. - # "regexpSimplify", + "regexpSimplify", + "returnAfterHttpError", "ruleguard", "singleCaseSwitch", "sliceClear", "sloppyLen", - # This seems like it might also be good, but a lot of existing code - # fails. - # "sloppyReassign", - "returnAfterHttpError", + "sloppyReassign", + "sloppyTestFuncName", "sloppyTypeAssert", "sortSlice", "sprintfQuotedString", "sqlQuery", "stringsCompare", + "stringConcatSimplify", "stringXbytes", "switchTrue", "syncMapLoadAndDelete", @@ -209,28 +183,40 @@ "underef", "unlabelStmt", "unlambda", - # I am not sure we would want this linter and a lot of existing - # code fails. # "unnamedResult", "unnecessaryBlock", "unnecessaryDefer", "unslice", "valSwap", "weakCond", + # Covered by nolintlint + # "whyNoLint" "wrapperFunc", "yodaStyleExpr", - # This requires explanations for "nolint" directives. This would be - # nice for gosec ones, but I am not sure we want it generally unless - # we can get the false positive rate lower. - # "whyNoLint" ] [linters-settings.gofumpt] extra-rules = true - lang-version = "1.18" + lang-version = "1.19" + +[linters-settings.gosec] + excludes = [ + # G104 - "Audit errors not checked." We use errcheck for this. + "G104", + + # G304 - "Potential file inclusion via variable" + "G304", + + # G306 - "Expect WriteFile permissions to be 0600 or less". + "G306", + + # Prohibits defer (*os.File).Close, which we allow when reading from file. + "G307", + ] [linters-settings.govet] "enable-all" = true + disable = ["shadow"] [linters-settings.lll] line-length = 120 @@ -247,8 +233,6 @@ ignore-generated-header = true severity = "warning" - # This might be nice but it is so common that it is hard - # to enable. # [[linters-settings.revive.rules]] # name = "add-constant" @@ -273,8 +257,10 @@ # [[linters-settings.revive.rules]] # name = "cognitive-complexity" - # Probably a good rule, but we have a lot of names that - # only have case differences. + [[linters-settings.revive.rules]] + name = "comment-spacings" + arguments = ["easyjson", "nolint"] + # [[linters-settings.revive.rules]] # name = "confusing-naming" @@ -293,6 +279,9 @@ # [[linters-settings.revive.rules]] # name = "cyclomatic" + [[linters-settings.revive.rules]] + name = "datarace" + # [[linters-settings.revive.rules]] # name = "deep-exit" @@ -332,8 +321,6 @@ # [[linters-settings.revive.rules]] # name = "file-header" - # We have a lot of flag parameters. This linter probably makes - # a good point, but we would need some cleanup or a lot of nolints. # [[linters-settings.revive.rules]] # name = "flag-parameter" @@ -373,7 +360,6 @@ [[linters-settings.revive.rules]] name = "modifies-value-receiver" - # We frequently use nested structs, particularly in tests. # [[linters-settings.revive.rules]] # name = "nested-structs" @@ -407,6 +393,9 @@ [[linters-settings.revive.rules]] name = "superfluous-else" + [[linters-settings.revive.rules]] + name = "time-equal" + [[linters-settings.revive.rules]] name = "time-naming" @@ -419,8 +408,6 @@ [[linters-settings.revive.rules]] name = "unexported-return" - # This is covered elsewhere and we want to ignore some - # functions such as fmt.Fprintf. # [[linters-settings.revive.rules]] # name = "unhandled-error" @@ -433,14 +420,11 @@ [[linters-settings.revive.rules]] name = "unused-parameter" - # We generally have unused receivers in tests for meeting the - # requirements of an interface. - # [[linters-settings.revive.rules]] - # name = "unused-receiver" + [[linters-settings.revive.rules]] + name = "unused-receiver" - # This probably makes sense after we upgrade to 1.18 - # [[linters-settings.revive.rules]] - # name = "use-any" + [[linters-settings.revive.rules]] + name = "use-any" [[linters-settings.revive.rules]] name = "useless-break" @@ -457,16 +441,12 @@ [linters-settings.unparam] check-exported = true +[issues] +exclude-use-default = false + [[issues.exclude-rules]] linters = [ "govet" ] - # we want to enable almost all govet rules. It is easier to just filter out - # the ones we don't want: - # - # * fieldalignment - way too noisy. Although it is very useful in particular - # cases where we are trying to use as little memory as possible, having - # it go off on every struct isn't helpful. - # * shadow - although often useful, it complains about _many_ err - # shadowing assignments and some others where shadowing is clear. - text = "^(fieldalignment|shadow)" + path = "_test.go" + text = "^fieldalignment" diff --git a/vendor/github.com/oschwald/maxminddb-golang/decoder.go b/vendor/github.com/oschwald/maxminddb-golang/decoder.go index 828c57ff..dd0f9ba3 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/decoder.go +++ b/vendor/github.com/oschwald/maxminddb-golang/decoder.go @@ -151,12 +151,12 @@ func (d *decoder) decodeFromType( result reflect.Value, depth int, ) (uint, error) { - result = d.indirect(result) + result = indirect(result) // For these types, size has a special meaning switch dtype { case _Bool: - return d.unmarshalBool(size, offset, result) + return unmarshalBool(size, offset, result) case _Map: return d.unmarshalMap(size, offset, result, depth) case _Pointer: @@ -203,7 +203,7 @@ func (d *decoder) decodeFromTypeToDeserializer( // For these types, size has a special meaning switch dtype { case _Bool: - v, offset := d.decodeBool(size, offset) + v, offset := decodeBool(size, offset) return offset, dser.Bool(v) case _Map: return d.decodeMapToDeserializer(size, offset, dser, depth) @@ -255,14 +255,14 @@ func (d *decoder) decodeFromTypeToDeserializer( } } -func (d *decoder) unmarshalBool(size, offset uint, result reflect.Value) (uint, error) { +func unmarshalBool(size, offset uint, result reflect.Value) (uint, error) { if size > 1 { return 0, newInvalidDatabaseError( "the MaxMind DB file's data section contains bad data (bool size of %v)", size, ) } - value, newOffset := d.decodeBool(size, offset) + value, newOffset := decodeBool(size, offset) switch result.Kind() { case reflect.Bool: @@ -281,7 +281,7 @@ func (d *decoder) unmarshalBool(size, offset uint, result reflect.Value) (uint, // heavily based on encoding/json as my original version had a subtle // bug. This method should be considered to be licensed under // https://golang.org/LICENSE -func (d *decoder) indirect(result reflect.Value) reflect.Value { +func indirect(result reflect.Value) reflect.Value { for { // Load value from interface, but only if the result will be // usefully addressable. @@ -415,7 +415,7 @@ func (d *decoder) unmarshalMap( result reflect.Value, depth int, ) (uint, error) { - result = d.indirect(result) + result = indirect(result) switch result.Kind() { default: return 0, newUnmarshalTypeError("map", result.Type()) @@ -425,7 +425,7 @@ func (d *decoder) unmarshalMap( return d.decodeMap(size, offset, result, depth) case reflect.Interface: if result.NumMethod() == 0 { - rv := reflect.ValueOf(make(map[string]interface{}, size)) + rv := reflect.ValueOf(make(map[string]any, size)) newOffset, err := d.decodeMap(size, offset, rv, depth) result.Set(rv) return newOffset, err @@ -458,7 +458,7 @@ func (d *decoder) unmarshalSlice( return d.decodeSlice(size, offset, result, depth) case reflect.Interface: if result.NumMethod() == 0 { - a := []interface{}{} + a := []any{} rv := reflect.ValueOf(&a).Elem() newOffset, err := d.decodeSlice(size, offset, rv, depth) result.Set(rv) @@ -551,7 +551,7 @@ func (d *decoder) unmarshalUint128(size, offset uint, result reflect.Value) (uin return newOffset, newUnmarshalTypeError(value, result.Type()) } -func (d *decoder) decodeBool(size, offset uint) (bool, uint) { +func decodeBool(size, offset uint) (bool, uint) { return size != 0, offset } @@ -596,18 +596,20 @@ func (d *decoder) decodeMap( mapType := result.Type() keyValue := reflect.New(mapType.Key()).Elem() elemType := mapType.Elem() - elemKind := elemType.Kind() var elemValue reflect.Value for i := uint(0); i < size; i++ { var key []byte var err error key, offset, err = d.decodeKey(offset) - if err != nil { return 0, err } - if !elemValue.IsValid() || elemKind == reflect.Interface { + if elemValue.IsValid() { + // After 1.20 is the minimum supported version, this can just be + // elemValue.SetZero() + reflectSetZero(elemValue) + } else { elemValue = reflect.New(elemType).Elem() } diff --git a/vendor/github.com/oschwald/maxminddb-golang/errors.go b/vendor/github.com/oschwald/maxminddb-golang/errors.go index 13278001..aeba906b 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/errors.go +++ b/vendor/github.com/oschwald/maxminddb-golang/errors.go @@ -15,7 +15,7 @@ func newOffsetError() InvalidDatabaseError { return InvalidDatabaseError{"unexpected end of database"} } -func newInvalidDatabaseError(format string, args ...interface{}) InvalidDatabaseError { +func newInvalidDatabaseError(format string, args ...any) InvalidDatabaseError { return InvalidDatabaseError{fmt.Sprintf(format, args...)} } @@ -26,11 +26,11 @@ func (e InvalidDatabaseError) Error() string { // UnmarshalTypeError is returned when the value in the database cannot be // assigned to the specified data type. type UnmarshalTypeError struct { - Value string // stringified copy of the database value that caused the error - Type reflect.Type // type of the value that could not be assign to + Type reflect.Type + Value string } -func newUnmarshalTypeError(value interface{}, rType reflect.Type) UnmarshalTypeError { +func newUnmarshalTypeError(value any, rType reflect.Type) UnmarshalTypeError { return UnmarshalTypeError{ Value: fmt.Sprintf("%v", value), Type: rType, diff --git a/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go b/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go index eeb2e05d..48b2e403 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go +++ b/vendor/github.com/oschwald/maxminddb-golang/mmap_unix.go @@ -1,5 +1,5 @@ -//go:build !windows && !appengine && !plan9 -// +build !windows,!appengine,!plan9 +//go:build !windows && !appengine && !plan9 && !js && !wasip1 && !wasi +// +build !windows,!appengine,!plan9,!js,!wasip1,!wasi package maxminddb diff --git a/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go b/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go index 661250ec..79133a7f 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go +++ b/vendor/github.com/oschwald/maxminddb-golang/mmap_windows.go @@ -1,3 +1,4 @@ +//go:build windows && !appengine // +build windows,!appengine package maxminddb diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader.go b/vendor/github.com/oschwald/maxminddb-golang/reader.go index 263cf64a..470845b2 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/reader.go +++ b/vendor/github.com/oschwald/maxminddb-golang/reader.go @@ -25,14 +25,14 @@ var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com") // All of the methods on Reader are thread-safe. The struct may be safely // shared across goroutines. type Reader struct { - hasMappedFile bool - buffer []byte nodeReader nodeReader + buffer []byte decoder decoder Metadata Metadata ipv4Start uint ipv4StartBitDepth int nodeOffsetMult uint + hasMappedFile bool } // Metadata holds the metadata decoded from the MaxMind DB file. In particular @@ -40,13 +40,13 @@ type Reader struct { // type and description, the IP version supported, and a slice of the natural // languages included. type Metadata struct { + Description map[string]string `maxminddb:"description"` + DatabaseType string `maxminddb:"database_type"` + Languages []string `maxminddb:"languages"` BinaryFormatMajorVersion uint `maxminddb:"binary_format_major_version"` BinaryFormatMinorVersion uint `maxminddb:"binary_format_minor_version"` BuildEpoch uint `maxminddb:"build_epoch"` - DatabaseType string `maxminddb:"database_type"` - Description map[string]string `maxminddb:"description"` IPVersion uint `maxminddb:"ip_version"` - Languages []string `maxminddb:"languages"` NodeCount uint `maxminddb:"node_count"` RecordSize uint `maxminddb:"record_size"` } @@ -130,7 +130,7 @@ func (r *Reader) setIPv4Start() { // because of type differences, an UnmarshalTypeError is returned. If the // database is invalid or otherwise cannot be read, an InvalidDatabaseError // is returned. -func (r *Reader) Lookup(ip net.IP, result interface{}) error { +func (r *Reader) Lookup(ip net.IP, result any) error { if r.buffer == nil { return errors.New("cannot call Lookup on a closed database") } @@ -152,7 +152,7 @@ func (r *Reader) Lookup(ip net.IP, result interface{}) error { // cannot be read, an InvalidDatabaseError is returned. func (r *Reader) LookupNetwork( ip net.IP, - result interface{}, + result any, ) (network *net.IPNet, ok bool, err error) { if r.buffer == nil { return nil, false, errors.New("cannot call Lookup on a closed database") @@ -204,7 +204,7 @@ func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet { // Decode the record at |offset| into |result|. The result value pointed to // must be a data value that corresponds to a record in the database. This may // include a struct representation of the data, a map capable of holding the -// data or an empty interface{} value. +// data or an empty any value. // // If result is a pointer to a struct, the struct need not include a field // for every value that may be in the database. If a field is not present in @@ -217,14 +217,14 @@ func (r *Reader) cidr(ip net.IP, prefixLength int) *net.IPNet { // the City database, all records of the same country will reference a // single representative record for that country. This uintptr behavior allows // clients to leverage this normalization in their own sub-record caching. -func (r *Reader) Decode(offset uintptr, result interface{}) error { +func (r *Reader) Decode(offset uintptr, result any) error { if r.buffer == nil { return errors.New("cannot call Decode on a closed database") } return r.decode(offset, result) } -func (r *Reader) decode(offset uintptr, result interface{}) error { +func (r *Reader) decode(offset uintptr, result any) error { rv := reflect.ValueOf(result) if rv.Kind() != reflect.Ptr || rv.IsNil() { return errors.New("result param must be a pointer") @@ -292,7 +292,7 @@ func (r *Reader) traverseTree(ip net.IP, node, bitCount uint) (uint, int) { return node, int(i) } -func (r *Reader) retrieveData(pointer uint, result interface{}) error { +func (r *Reader) retrieveData(pointer uint, result any) error { offset, err := r.resolveDataPointer(pointer) if err != nil { return err diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go b/vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go deleted file mode 100644 index c6385d80..00000000 --- a/vendor/github.com/oschwald/maxminddb-golang/reader_appengine.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build appengine plan9 - -package maxminddb - -import "io/ioutil" - -// Open takes a string path to a MaxMind DB file and returns a Reader -// structure or an error. The database file is opened using a memory map, -// except on Google App Engine where mmap is not supported; there the database -// is loaded into memory. Use the Close method on the Reader object to return -// the resources to the system. -func Open(file string) (*Reader, error) { - bytes, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - - return FromBytes(bytes) -} - -// Close unmaps the database file from virtual memory and returns the -// resources to the system. If called on a Reader opened using FromBytes -// or Open on Google App Engine, this method sets the underlying buffer -// to nil, returning the resources to the system. -func (r *Reader) Close() error { - r.buffer = nil - return nil -} diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader_memory.go b/vendor/github.com/oschwald/maxminddb-golang/reader_memory.go new file mode 100644 index 00000000..4ebb3473 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/reader_memory.go @@ -0,0 +1,26 @@ +//go:build appengine || plan9 || js || wasip1 || wasi +// +build appengine plan9 js wasip1 wasi + +package maxminddb + +import "io/ioutil" + +// Open takes a string path to a MaxMind DB file and returns a Reader +// structure or an error. The database file is opened using a memory map +// on supported platforms. On platforms without memory map support, such +// as WebAssembly or Google App Engine, the database is loaded into memory. +// Use the Close method on the Reader object to return the resources to the system. +func Open(file string) (*Reader, error) { + bytes, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + return FromBytes(bytes) +} + +// Close returns the resources used by the database to the system. +func (r *Reader) Close() error { + r.buffer = nil + return nil +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader_other.go b/vendor/github.com/oschwald/maxminddb-golang/reader_mmap.go similarity index 70% rename from vendor/github.com/oschwald/maxminddb-golang/reader_other.go rename to vendor/github.com/oschwald/maxminddb-golang/reader_mmap.go index 0ed9de10..1d083019 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/reader_other.go +++ b/vendor/github.com/oschwald/maxminddb-golang/reader_mmap.go @@ -1,5 +1,5 @@ -//go:build !appengine && !plan9 -// +build !appengine,!plan9 +//go:build !appengine && !plan9 && !js && !wasip1 && !wasi +// +build !appengine,!plan9,!js,!wasip1,!wasi package maxminddb @@ -9,10 +9,10 @@ import ( ) // Open takes a string path to a MaxMind DB file and returns a Reader -// structure or an error. The database file is opened using a memory map, -// except on Google App Engine where mmap is not supported; there the database -// is loaded into memory. Use the Close method on the Reader object to return -// the resources to the system. +// structure or an error. The database file is opened using a memory map +// on supported platforms. On platforms without memory map support, such +// as WebAssembly or Google App Engine, the database is loaded into memory. +// Use the Close method on the Reader object to return the resources to the system. func Open(file string) (*Reader, error) { mapFile, err := os.Open(file) if err != nil { @@ -51,9 +51,7 @@ func Open(file string) (*Reader, error) { return reader, nil } -// Close unmaps the database file from virtual memory and returns the -// resources to the system. If called on a Reader opened using FromBytes -// or Open on Google App Engine, this method does nothing. +// Close returns the resources used by the database to the system. func (r *Reader) Close() error { var err error if r.hasMappedFile { diff --git a/vendor/github.com/oschwald/maxminddb-golang/set_zero_120.go b/vendor/github.com/oschwald/maxminddb-golang/set_zero_120.go new file mode 100644 index 00000000..33b9dff9 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/set_zero_120.go @@ -0,0 +1,10 @@ +//go:build go1.20 +// +build go1.20 + +package maxminddb + +import "reflect" + +func reflectSetZero(v reflect.Value) { + v.SetZero() +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/set_zero_pre120.go b/vendor/github.com/oschwald/maxminddb-golang/set_zero_pre120.go new file mode 100644 index 00000000..6639de73 --- /dev/null +++ b/vendor/github.com/oschwald/maxminddb-golang/set_zero_pre120.go @@ -0,0 +1,10 @@ +//go:build !go1.20 +// +build !go1.20 + +package maxminddb + +import "reflect" + +func reflectSetZero(v reflect.Value) { + v.Set(reflect.Zero(v.Type())) +} diff --git a/vendor/github.com/oschwald/maxminddb-golang/traverse.go b/vendor/github.com/oschwald/maxminddb-golang/traverse.go index 7009ec14..657e2c40 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/traverse.go +++ b/vendor/github.com/oschwald/maxminddb-golang/traverse.go @@ -14,11 +14,10 @@ type netNode struct { // Networks represents a set of subnets that we are iterating over. type Networks struct { - reader *Reader - nodes []netNode // Nodes we still have to visit. - lastNode netNode - err error - + err error + reader *Reader + nodes []netNode + lastNode netNode skipAliasedNetworks bool } @@ -159,7 +158,7 @@ func (n *Networks) Next() bool { // Network returns the current network or an error if there is a problem // decoding the data for the network. It takes a pointer to a result value to // decode the network's data into. -func (n *Networks) Network(result interface{}) (*net.IPNet, error) { +func (n *Networks) Network(result any) (*net.IPNet, error) { if n.err != nil { return nil, n.err } diff --git a/vendor/github.com/oschwald/maxminddb-golang/verifier.go b/vendor/github.com/oschwald/maxminddb-golang/verifier.go index 88381d74..b14b3e48 100644 --- a/vendor/github.com/oschwald/maxminddb-golang/verifier.go +++ b/vendor/github.com/oschwald/maxminddb-golang/verifier.go @@ -137,7 +137,7 @@ func (v *verifier) verifyDataSection(offsets map[uint]bool) error { var offset uint bufferLen := uint(len(decoder.buffer)) for offset < bufferLen { - var data interface{} + var data any rv := reflect.ValueOf(&data) newOffset, err := decoder.decode(offset, rv, 0) if err != nil { @@ -189,8 +189,8 @@ func (v *verifier) verifyDataSection(offsets map[uint]bool) error { func testError( field string, - expected interface{}, - actual interface{}, + expected any, + actual any, ) error { return newInvalidDatabaseError( "%v - Expected: %v Actual: %v", diff --git a/vendor/github.com/posener/script/cat.go b/vendor/github.com/posener/script/cat.go index 49e2c74e..6ec3e5a5 100644 --- a/vendor/github.com/posener/script/cat.go +++ b/vendor/github.com/posener/script/cat.go @@ -1,11 +1,10 @@ package script import ( + "errors" "fmt" "io" "os" - - "github.com/hashicorp/go-multierror" ) // Cat outputs the contents of the given files. @@ -15,13 +14,13 @@ func Cat(paths ...string) Stream { var ( readers []io.Reader closers multicloser - errors *multierror.Error + merr error ) for _, path := range paths { f, err := os.Open(path) if err != nil { - errors = multierror.Append(errors, fmt.Errorf("open path %s: %v", path, err)) + merr = errors.Join(merr, fmt.Errorf("open path %s: %w", path, err)) } else { readers = append(readers, f) closers = append(closers, f) @@ -31,19 +30,18 @@ func Cat(paths ...string) Stream { return Stream{ r: readcloser{Reader: io.MultiReader(readers...), Closer: closers}, stage: "cat", - err: errors.ErrorOrNil(), + err: merr, } - } type multicloser []io.Closer func (mc multicloser) Close() error { - var errors *multierror.Error + var merr error for _, c := range mc { if err := c.Close(); err != nil { - errors = multierror.Append(errors, err) + merr = errors.Join(merr, err) } } - return errors.ErrorOrNil() + return merr } diff --git a/vendor/github.com/posener/script/exec.go b/vendor/github.com/posener/script/exec.go index 53ea02cd..79d34be8 100644 --- a/vendor/github.com/posener/script/exec.go +++ b/vendor/github.com/posener/script/exec.go @@ -1,12 +1,10 @@ package script import ( + "errors" "fmt" "io" - "io/ioutil" "os/exec" - - "github.com/hashicorp/go-multierror" ) // Exec executes a command and returns a stream of the stdout of the command. @@ -51,7 +49,7 @@ func (e exe) Name() string { func (e exe) Pipe(stdin io.Reader) (io.Reader, error) { cmd := exec.Command(e.cmd, e.args...) - var errors *multierror.Error + var merr error // Pipe previous stdin if available. if stdin != nil { @@ -61,23 +59,23 @@ func (e exe) Pipe(stdin io.Reader) (io.Reader, error) { // Pipe stdout to the current command output. cmdOut, err := cmd.StdoutPipe() if err != nil { - errors = multierror.Append(errors, fmt.Errorf("pipe stdout: %v", err)) + merr = errors.Join(merr, fmt.Errorf("pipe stdout: %w", err)) } if e.stderr == nil { - e.stderr = ioutil.Discard + e.stderr = io.Discard } cmd.Stderr = e.stderr // start the process err = cmd.Start() if err != nil { - errors = multierror.Append(errors, fmt.Errorf("start process: %v", err)) + merr = errors.Join(merr, fmt.Errorf("start process: %w", err)) } return readcloser{ Reader: cmdOut, Closer: closerFn(func() error { return cmd.Wait() }), - }, errors.ErrorOrNil() + }, merr } type closerFn func() error diff --git a/vendor/github.com/posener/script/from.go b/vendor/github.com/posener/script/from.go index 91c10d76..71d3f50b 100644 --- a/vendor/github.com/posener/script/from.go +++ b/vendor/github.com/posener/script/from.go @@ -3,7 +3,6 @@ package script import ( "bytes" "io" - "io/ioutil" "os" "strings" ) @@ -22,7 +21,7 @@ func Writer(name string, writer func(io.Writer) error) Stream { // Stdin starts a stream from stdin. func Stdin() Stream { - stdin := ioutil.NopCloser(os.Stdin) // Prevent closing of stdin. + stdin := io.NopCloser(os.Stdin) // Prevent closing of stdin. return From("stdin", stdin) } diff --git a/vendor/github.com/posener/script/ls.go b/vendor/github.com/posener/script/ls.go index d9b3f462..0d454cd8 100644 --- a/vendor/github.com/posener/script/ls.go +++ b/vendor/github.com/posener/script/ls.go @@ -1,10 +1,9 @@ package script import ( + "errors" "fmt" - "github.com/hashicorp/go-multierror" "io" - "io/ioutil" "os" "path/filepath" ) @@ -47,14 +46,14 @@ func Ls(paths ...string) Files { } var ( - files []FileInfo - errors *multierror.Error + files []FileInfo + merr error ) for _, path := range paths { info, err := os.Stat(path) if err != nil { - errors = multierror.Append(errors, fmt.Errorf("stat path: %s", err)) + merr = errors.Join(merr, fmt.Errorf("stat path %s: %w", path, err)) continue } @@ -65,13 +64,17 @@ func Ls(paths ...string) Files { } // Path is a directory. - infos, err := ioutil.ReadDir(path) + dirEntries, err := os.ReadDir(path) if err != nil { - errors = multierror.Append(errors, fmt.Errorf("read dir: %s", err)) + merr = errors.Join(merr, fmt.Errorf("read dir %s: %w", path, err)) continue } - for _, info := range infos { + for _, entry := range dirEntries { + info, err := entry.Info() + if err != nil { + merr = errors.Join(merr, fmt.Errorf("failed to get file info from dir entry: %w", err)) + } files = append(files, FileInfo{Path: filepath.Join(path, info.Name()), FileInfo: info}) } } @@ -80,7 +83,7 @@ func Ls(paths ...string) Files { Stream: Stream{ stage: fmt.Sprintf("ls (%+v)", paths), r: &filesReader{files: files}, - err: errors.ErrorOrNil(), + err: merr, }, Files: files, } diff --git a/vendor/github.com/posener/script/modify.go b/vendor/github.com/posener/script/modify.go index bebcf81a..2a5a6f6e 100644 --- a/vendor/github.com/posener/script/modify.go +++ b/vendor/github.com/posener/script/modify.go @@ -93,6 +93,11 @@ func (m *modPipe) Read(out []byte) (n int, err error) { } m.partialOut, n = copyBytes(out, line) + // If n is zero and err is nil, don't return. Otherwise, scanner.Scanners will + // return io.ErrNoProgress when (0, nil) is returned too many times. + if n == 0 && m.err == nil { + continue + } return n, nil } } diff --git a/vendor/github.com/posener/script/sort.go b/vendor/github.com/posener/script/sort.go index 037290f8..18060694 100644 --- a/vendor/github.com/posener/script/sort.go +++ b/vendor/github.com/posener/script/sort.go @@ -2,11 +2,10 @@ package script import ( "bufio" + "errors" "fmt" "sort" "strings" - - "github.com/hashicorp/go-multierror" ) // Sort returns a stream with lines ordered alphabetically. @@ -14,15 +13,15 @@ import ( // Shell command: `wc`. func (s Stream) Sort(reverse bool) Stream { var ( - lines []string - errors *multierror.Error + lines []string + merr error ) scanner := bufio.NewScanner(s.r) for scanner.Scan() { lines = append(lines, scanner.Text()) } if err := scanner.Err(); err != nil { - errors = multierror.Append(errors, fmt.Errorf("scanning stream: %s", err)) + merr = errors.Join(merr, fmt.Errorf("scanning stream: %w", err)) } sort.Slice(lines, func(i, j int) bool { return (lines[i] < lines[j]) != reverse }) @@ -31,13 +30,13 @@ func (s Stream) Sort(reverse bool) Stream { for _, line := range lines { _, err := out.WriteString(line + "\n") if err != nil { - errors = multierror.Append(errors, fmt.Errorf("writing line %q: %s", line, err)) + merr = errors.Join(merr, fmt.Errorf("writing line %q: %w", line, err)) } } return Stream{ stage: fmt.Sprintf("sort(%v)", reverse), r: strings.NewReader(out.String()), - err: errors.ErrorOrNil(), + err: merr, } } diff --git a/vendor/github.com/posener/script/stream.go b/vendor/github.com/posener/script/stream.go index 1e402a1c..09843745 100644 --- a/vendor/github.com/posener/script/stream.go +++ b/vendor/github.com/posener/script/stream.go @@ -15,10 +15,9 @@ package script import ( + "errors" "io" "reflect" - - "github.com/hashicorp/go-multierror" ) // Stream is a chain of operations on a stream of bytes. The stdout of each operation in the stream @@ -50,18 +49,18 @@ func (s Stream) Read(b []byte) (int, error) { // Close closes all the stages in the stream and return the errors that occurred in all of the // stages. func (s Stream) Close() error { - var errors *multierror.Error + var merr error for cur := &s; cur != nil; cur = cur.parent { if cur.err != nil { - errors = multierror.Append(errors, cur.err) + merr = errors.Join(merr, cur.err) } if closer, ok := cur.r.(io.Closer); ok { if err := closer.Close(); err != nil { - errors = multierror.Append(errors, err) + merr = errors.Join(merr, err) } } } - return errors.ErrorOrNil() + return merr } // Through passes the current stream through a pipe. This function can be used to add custom diff --git a/vendor/github.com/posener/script/to.go b/vendor/github.com/posener/script/to.go index e1bab6dd..9ffd7de4 100644 --- a/vendor/github.com/posener/script/to.go +++ b/vendor/github.com/posener/script/to.go @@ -2,35 +2,31 @@ package script import ( "bytes" + "errors" "io" - "io/ioutil" "os" "path/filepath" - - "github.com/hashicorp/go-multierror" ) // To writes the output of the stream to an io.Writer and closes it. func (s Stream) To(w io.Writer) error { - var errors *multierror.Error + var merr error if _, err := io.Copy(w, s); err != nil { - errors = multierror.Append(errors, err) + merr = errors.Join(merr, err) } if err := s.Close(); err != nil { - errors = multierror.Append(errors, err) + merr = errors.Join(merr, err) } - return errors.ErrorOrNil() + return merr } func (s Stream) Iterate(iterator func(line []byte) error) error { return s.Modify(ModifyFn(func(line []byte) (modifed []byte, err error) { err = iterator(line) return nil, err - })).To(ioutil.Discard) + })).To(io.Discard) } -type iterator struct{} - // ToStdout pipes the stdout of the stream to screen. func (s Stream) ToStdout() error { return s.To(os.Stdout) @@ -67,7 +63,7 @@ func (s Stream) AppendFile(path string) error { // ToTempFile dumps the output of the stream to a temporary file and returns the temporary files' // path. func (s Stream) ToTempFile() (path string, err error) { - f, err := ioutil.TempFile("", "script-") + f, err := os.CreateTemp("", "script-") if err != nil { return "", err } @@ -77,7 +73,7 @@ func (s Stream) ToTempFile() (path string, err error) { // Discard executes the stream pipeline but discards the output. func (s Stream) Discard() error { - return s.To(ioutil.Discard) + return s.To(io.Discard) } func File(path string) (io.WriteCloser, error) { diff --git a/vendor/github.com/posener/script/wc.go b/vendor/github.com/posener/script/wc.go index 391e0ee6..f7c0aa96 100644 --- a/vendor/github.com/posener/script/wc.go +++ b/vendor/github.com/posener/script/wc.go @@ -2,10 +2,9 @@ package script import ( "bufio" + "errors" "fmt" "strings" - - "github.com/hashicorp/go-multierror" ) // Count represents the output of `wc` shell command. @@ -23,8 +22,8 @@ func (s Stream) Wc() Count { defer s.Close() var ( - count Count - errors *multierror.Error + count Count + merr error ) scanner := bufio.NewScanner(s) for scanner.Scan() { @@ -33,12 +32,13 @@ func (s Stream) Wc() Count { count.Words += countWords(scanner.Text()) } if err := scanner.Err(); err != nil { - errors = multierror.Append(errors, fmt.Errorf("scanning stream: %s", err)) + merr = errors.Join(merr, fmt.Errorf("scanning stream: %w", err)) } count.Stream = Stream{ stage: "wc", r: strings.NewReader(count.String()), + err: merr, } return count } diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go index 95d8e59d..b774da88 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -352,9 +352,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 +364,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 +377,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 +389,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 +402,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 +414,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_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index 7880b8f9..84dbd6c7 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -22,9 +22,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 +56,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 +66,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 +81,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 +90,27 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) } +// 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 convertable 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 +120,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 +143,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 +164,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 +172,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 +225,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 +244,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 +256,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 +270,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 +283,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 +295,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 +307,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 +319,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 +331,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 +343,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 +353,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 +395,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 +407,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 +419,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 +431,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 +451,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 +462,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 +472,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 +484,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 +497,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 +509,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 +519,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 +538,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 +561,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 +574,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 +586,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 +599,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() @@ -576,7 +618,7 @@ func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interf // 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 +628,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 +638,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 +649,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. @@ -621,7 +663,7 @@ func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, // NotSubsetf asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // -// 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], "But [1, 3, 4] does not contain [1, 2]", "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 +681,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 +693,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 +704,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 +714,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 +725,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 +736,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. @@ -708,7 +750,7 @@ func Samef(t TestingT, expected interface{}, actual interface{}, msg string, arg // Subsetf asserts that the specified list(array, slice...) contains all // elements given in the specified subset(array, slice...). // -// 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], "But [1, 2, 3] does contain [1, 2]", "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 +760,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 +770,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 +780,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 339515b8..b1d94aec 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -30,9 +30,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 +43,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 +98,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 +109,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 +119,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 +134,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 +146,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 +155,44 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a return EqualErrorf(a.t, theError, errString, msg, args...) } +// 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 convertable 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() @@ -169,7 +203,7 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn // EqualValuesf asserts that two objects are equal or convertable 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 +213,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 +227,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 +259,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 +271,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 +300,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 +314,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 +322,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 +385,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 +395,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 +437,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 +447,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 +475,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 +487,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 +500,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 +513,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 +526,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 +539,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 +552,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 +565,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 +577,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 +589,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 +601,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 +613,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 +625,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 +637,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 +649,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 +661,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 +673,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 +683,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 +693,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 +735,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 +777,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 +789,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 +801,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 +813,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 +825,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 +837,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 +849,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 +861,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 +889,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 +899,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 +910,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 +921,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 +931,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 +943,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 +956,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 +969,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 +981,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 +992,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 +1004,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 +1015,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 +1025,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 +1035,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 +1063,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 +1076,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 +1108,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 +1121,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 +1134,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 +1147,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 +1159,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 +1172,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 +1182,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 +1192,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). @@ -1139,7 +1223,7 @@ func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...in // 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 +1233,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 +1243,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 +1253,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 +1263,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 +1274,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 +1285,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 +1298,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. @@ -1228,7 +1312,7 @@ func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg stri // NotSubset asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // -// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1239,7 +1323,7 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs // NotSubsetf asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // -// 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], "But [1, 3, 4] does not contain [1, 2]", "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 +1349,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 +1361,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 +1373,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 +1384,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 +1395,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 +1405,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 +1415,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 +1426,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 +1437,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 +1448,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 +1459,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 +1472,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. @@ -1402,7 +1486,7 @@ func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, // Subset asserts that the specified list(array, slice...) contains all // elements given in the specified subset(array, slice...). // -// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1413,7 +1497,7 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ... // Subsetf asserts that the specified list(array, slice...) contains all // elements given in the specified subset(array, slice...). // -// 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], "But [1, 2, 3] does contain [1, 2]", "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 +1507,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 +1517,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 +1527,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 +1537,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 +1547,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 +1557,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 75944878..00df62a0 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 fa1245b1..a55d1bba 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -8,7 +8,6 @@ import ( "fmt" "math" "os" - "path/filepath" "reflect" "regexp" "runtime" @@ -76,6 +75,77 @@ 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: + 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. +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 { @@ -141,12 +211,11 @@ func CallerInfo() []string { } parts := strings.Split(file, "/") - file = parts[len(parts)-1] if len(parts) > 1 { + filename := parts[len(parts)-1] dir := parts[len(parts)-2] - if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { - path, _ := filepath.Abs(file) - callers = append(callers, fmt.Sprintf("%s:%d", path, line)) + if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" { + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) } } @@ -273,7 +342,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 @@ -296,7 +365,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() @@ -328,7 +397,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 @@ -369,7 +438,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. @@ -389,7 +458,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. @@ -457,7 +526,7 @@ func truncatingFormat(data interface{}) string { // EqualValues asserts that two objects are equal or convertable 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() @@ -475,9 +544,53 @@ 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.Struct { + return Fail(t, fmt.Sprintf("Types expected to both be 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 \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() @@ -496,7 +609,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 @@ -530,7 +643,7 @@ func isNil(object interface{}) bool { []reflect.Kind{ reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, - reflect.Ptr, reflect.Slice}, + reflect.Ptr, reflect.Slice, reflect.UnsafePointer}, kind) if isNilableKind && value.IsNil() { @@ -542,7 +655,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 @@ -585,7 +698,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 { @@ -602,9 +715,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 { @@ -633,7 +746,7 @@ func getLen(x interface{}) (ok bool, length 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{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -651,7 +764,7 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) // 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 { @@ -666,7 +779,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 { @@ -681,7 +794,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). @@ -704,7 +817,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() @@ -763,9 +876,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() @@ -786,9 +899,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() @@ -796,10 +909,10 @@ 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 @@ -809,7 +922,7 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) // Subset asserts that the specified list(array, slice...) contains all // elements given in the specified subset(array, slice...). // -// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() @@ -818,49 +931,44 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return true // we consider nil to be equal to the nil set } - defer func() { - if e := recover(); e != nil { - ok = false - } - }() - listKind := reflect.TypeOf(list).Kind() - subsetKind := reflect.TypeOf(subset).Kind() - if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } + subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } - subsetValue := reflect.ValueOf(subset) if subsetKind == reflect.Map && listKind == reflect.Map { - listValue := reflect.ValueOf(list) - subsetKeys := subsetValue.MapKeys() + subsetMap := reflect.ValueOf(subset) + actualMap := reflect.ValueOf(list) - for i := 0; i < len(subsetKeys); i++ { - subsetKey := subsetKeys[i] - subsetElement := subsetValue.MapIndex(subsetKey).Interface() - listElement := listValue.MapIndex(subsetKey).Interface() + for _, k := range subsetMap.MapKeys() { + ev := subsetMap.MapIndex(k) + av := actualMap.MapIndex(k) - if !ObjectsAreEqual(subsetElement, listElement) { - return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, subsetElement), msgAndArgs...) + if !av.IsValid() { + return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) + } + if !ObjectsAreEqual(ev.Interface(), av.Interface()) { + return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) } } return true } - for i := 0; i < subsetValue.Len(); i++ { - element := subsetValue.Index(i).Interface() + subsetList := reflect.ValueOf(subset) + for i := 0; i < subsetList.Len(); i++ { + element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...) } } @@ -870,7 +978,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok // NotSubset asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // -// 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], "But [1, 3, 4] does not contain [1, 2]") func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { if h, ok := t.(tHelper); ok { h.Helper() @@ -879,34 +987,28 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) } - defer func() { - if e := recover(); e != nil { - ok = false - } - }() - listKind := reflect.TypeOf(list).Kind() - subsetKind := reflect.TypeOf(subset).Kind() - if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } + subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } - subsetValue := reflect.ValueOf(subset) if subsetKind == reflect.Map && listKind == reflect.Map { - listValue := reflect.ValueOf(list) - subsetKeys := subsetValue.MapKeys() + subsetMap := reflect.ValueOf(subset) + actualMap := reflect.ValueOf(list) - for i := 0; i < len(subsetKeys); i++ { - subsetKey := subsetKeys[i] - subsetElement := subsetValue.MapIndex(subsetKey).Interface() - listElement := listValue.MapIndex(subsetKey).Interface() + for _, k := range subsetMap.MapKeys() { + ev := subsetMap.MapIndex(k) + av := actualMap.MapIndex(k) - if !ObjectsAreEqual(subsetElement, listElement) { + if !av.IsValid() { + return true + } + if !ObjectsAreEqual(ev.Interface(), av.Interface()) { return true } } @@ -914,8 +1016,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) } - for i := 0; i < subsetValue.Len(); i++ { - element := subsetValue.Index(i).Interface() + subsetList := reflect.ValueOf(subset) + for i := 0; i < subsetList.Len(); i++ { + element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) @@ -1060,7 +1163,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() @@ -1076,7 +1179,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() @@ -1097,7 +1200,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() @@ -1117,7 +1220,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() @@ -1132,7 +1235,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() @@ -1148,7 +1251,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() @@ -1207,7 +1310,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() @@ -1380,10 +1483,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 { @@ -1397,10 +1500,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 { @@ -1415,8 +1518,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() @@ -1438,8 +1541,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() @@ -1472,8 +1575,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() @@ -1490,8 +1593,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() @@ -1603,7 +1706,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() @@ -1726,7 +1829,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() @@ -1756,10 +1859,93 @@ 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 (c *CollectT) FailNow() { + panic("Assertion failed") +} + +// Reset clears the collected errors. +func (c *CollectT) Reset() { + c.errors = nil +} + +// Copy copies the collected errors to the supplied t. +func (c *CollectT) Copy(t TestingT) { + if tt, ok := t.(tHelper); ok { + tt.Helper() + } + for _, err := range c.errors { + t.Errorf("%v", err) + } +} + +// 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() + } + + collect := new(CollectT) + ch := make(chan bool, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + collect.Copy(t) + return Fail(t, "Condition never satisfied", msgAndArgs...) + case <-tick: + tick = nil + collect.Reset() + go func() { + condition(collect) + ch <- len(collect.errors) == 0 + }() + case v := <-ch: + if v { + return true + } + 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 c9dccc4d..4953981d 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 4ed341dd..d8038c28 100644 --- a/vendor/github.com/stretchr/testify/assert/http_assertions.go +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -124,7 +124,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 { @@ -144,7 +144,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 { diff --git a/vendor/go4.org/intern/LICENSE b/vendor/go4.org/intern/LICENSE deleted file mode 100644 index b0ab8921..00000000 --- a/vendor/go4.org/intern/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2020, Brad Fitzpatrick -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. - -3. Neither the name of the copyright holder 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 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/go4.org/intern/README.md b/vendor/go4.org/intern/README.md deleted file mode 100644 index 758699dc..00000000 --- a/vendor/go4.org/intern/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# go4.org/intern [![Go Reference](https://pkg.go.dev/badge/go4.org/intern.svg)](https://pkg.go.dev/go4.org/intern) - -## What - -Package intern lets you make smaller comparable values by boxing a larger comparable value (such as a string header) down into a single globally unique pointer. - -Docs: https://pkg.go.dev/go4.org/intern - -## Status - -This package is mature and stable. However, it depends on the implementation details of the Go runtime. Use with care. - -This package is a core, low-level package with no substantive dependencies. - -We take code review, testing, dependencies, and performance seriously, similar to Go's standard library or the golang.org/x repos. - -## Motivation - -Package intern was initially created for [package inet.af/netaddr](https://pkg.go.dev/inet.af/netaddr). diff --git a/vendor/go4.org/intern/intern.go b/vendor/go4.org/intern/intern.go deleted file mode 100644 index 536014cd..00000000 --- a/vendor/go4.org/intern/intern.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2020 Brad Fitzpatrick. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package intern lets you make smaller comparable values by boxing -// a larger comparable value (such as a 16 byte string header) down -// into a globally unique 8 byte pointer. -// -// The globally unique pointers are garbage collected with weak -// references and finalizers. This package hides that. -// -// The GitHub repo is https://github.com/go4org/intern -package intern // import "go4.org/intern" - -import ( - "os" - "runtime" - "strconv" - "sync" - "unsafe" - - _ "go4.org/unsafe/assume-no-moving-gc" -) - -// A Value pointer is the handle to an underlying comparable value. -// See func Get for how Value pointers may be used. -type Value struct { - _ [0]func() // prevent people from accidentally using value type as comparable - cmpVal interface{} - // resurrected is guarded by mu (for all instances of Value). - // It is set true whenever v is synthesized from a uintptr. - resurrected bool -} - -// Get returns the comparable value passed to the Get func -// that returned v. -func (v *Value) Get() interface{} { return v.cmpVal } - -// key is a key in our global value map. -// It contains type-specialized fields to avoid allocations -// when converting common types to empty interfaces. -type key struct { - s string - cmpVal interface{} - // isString reports whether key contains a string. - // Without it, the zero value of key is ambiguous. - isString bool -} - -// keyFor returns a key to use with cmpVal. -func keyFor(cmpVal interface{}) key { - if s, ok := cmpVal.(string); ok { - return key{s: s, isString: true} - } - return key{cmpVal: cmpVal} -} - -// Value returns a *Value built from k. -func (k key) Value() *Value { - if k.isString { - return &Value{cmpVal: k.s} - } - return &Value{cmpVal: k.cmpVal} -} - -var ( - // mu guards valMap, a weakref map of *Value by underlying value. - // It also guards the resurrected field of all *Values. - mu sync.Mutex - valMap = map[key]uintptr{} // to uintptr(*Value) - valSafe = safeMap() // non-nil in safe+leaky mode -) - -// safeMap returns a non-nil map if we're in safe-but-leaky mode, -// as controlled by GO4_INTERN_SAFE_BUT_LEAKY. -func safeMap() map[key]*Value { - if v, _ := strconv.ParseBool(os.Getenv("GO4_INTERN_SAFE_BUT_LEAKY")); v { - return map[key]*Value{} - } - return nil -} - -// Get returns a pointer representing the comparable value cmpVal. -// -// The returned pointer will be the same for Get(v) and Get(v2) -// if and only if v == v2, and can be used as a map key. -func Get(cmpVal interface{}) *Value { - return get(keyFor(cmpVal)) -} - -// GetByString is identical to Get, except that it is specialized for strings. -// This avoids an allocation from putting a string into an interface{} -// to pass as an argument to Get. -func GetByString(s string) *Value { - return get(key{s: s, isString: true}) -} - -// We play unsafe games that violate Go's rules (and assume a non-moving -// collector). So we quiet Go here. -// See the comment below Get for more implementation details. -//go:nocheckptr -func get(k key) *Value { - mu.Lock() - defer mu.Unlock() - - var v *Value - if valSafe != nil { - v = valSafe[k] - } else if addr, ok := valMap[k]; ok { - v = (*Value)((unsafe.Pointer)(addr)) - v.resurrected = true - } - if v != nil { - return v - } - v = k.Value() - if valSafe != nil { - valSafe[k] = v - } else { - // SetFinalizer before uintptr conversion (theoretical concern; - // see https://github.com/go4org/intern/issues/13) - runtime.SetFinalizer(v, finalize) - valMap[k] = uintptr(unsafe.Pointer(v)) - } - return v -} - -func finalize(v *Value) { - mu.Lock() - defer mu.Unlock() - if v.resurrected { - // We lost the race. Somebody resurrected it while we - // were about to finalize it. Try again next round. - v.resurrected = false - runtime.SetFinalizer(v, finalize) - return - } - delete(valMap, keyFor(v.cmpVal)) -} - -// Interning is simple if you don't require that unused values be -// garbage collectable. But we do require that; we don't want to be -// DOS vector. We do this by using a uintptr to hide the pointer from -// the garbage collector, and using a finalizer to eliminate the -// pointer when no other code is using it. -// -// The obvious implementation of this is to use a -// map[interface{}]uintptr-of-*interface{}, and set up a finalizer to -// delete from the map. Unfortunately, this is racy. Because pointers -// are being created in violation of Go's unsafety rules, it's -// possible to create a pointer to a value concurrently with the GC -// concluding that the value can be collected. There are other races -// that break the equality invariant as well, but the use-after-free -// will cause a runtime crash. -// -// To make this work, the finalizer needs to know that no references -// have been unsafely created since the finalizer was set up. To do -// this, values carry a "resurrected" sentinel, which gets set -// whenever a pointer is unsafely created. If the finalizer encounters -// the sentinel, it clears the sentinel and delays collection for one -// additional GC cycle, by re-installing itself as finalizer. This -// ensures that the unsafely created pointer is visible to the GC, and -// will correctly prevent collection. -// -// This technique does mean that interned values that get reused take -// at least 3 GC cycles to fully collect (1 to clear the sentinel, 1 -// to clean up the unsafe map, 1 to be actually deleted). -// -// @ianlancetaylor commented in -// https://github.com/golang/go/issues/41303#issuecomment-717401656 -// that it is possible to implement weak references in terms of -// finalizers without unsafe. Unfortunately, the approach he outlined -// does not work here, for two reasons. First, there is no way to -// construct a strong pointer out of a weak pointer; our map stores -// weak pointers, but we must return strong pointers to callers. -// Second, and more fundamentally, we must return not just _a_ strong -// pointer to callers, but _the same_ strong pointer to callers. In -// order to return _the same_ strong pointer to callers, we must track -// it, which is exactly what we cannot do with strong pointers. -// -// See https://github.com/inetaf/netaddr/issues/53 for more -// discussion, and https://github.com/go4org/intern/issues/2 for an -// illustration of the subtleties at play. diff --git a/vendor/inet.af/netaddr/.gitignore b/vendor/go4.org/netipx/.gitignore similarity index 100% rename from vendor/inet.af/netaddr/.gitignore rename to vendor/go4.org/netipx/.gitignore diff --git a/vendor/inet.af/netaddr/.gitmodules b/vendor/go4.org/netipx/.gitmodules similarity index 100% rename from vendor/inet.af/netaddr/.gitmodules rename to vendor/go4.org/netipx/.gitmodules diff --git a/vendor/inet.af/netaddr/AUTHORS b/vendor/go4.org/netipx/AUTHORS similarity index 100% rename from vendor/inet.af/netaddr/AUTHORS rename to vendor/go4.org/netipx/AUTHORS diff --git a/vendor/inet.af/netaddr/LICENSE b/vendor/go4.org/netipx/LICENSE similarity index 100% rename from vendor/inet.af/netaddr/LICENSE rename to vendor/go4.org/netipx/LICENSE diff --git a/vendor/go4.org/netipx/README.md b/vendor/go4.org/netipx/README.md new file mode 100644 index 00000000..74bfa417 --- /dev/null +++ b/vendor/go4.org/netipx/README.md @@ -0,0 +1,26 @@ +# netipx [![Test Status](https://github.com/go4org/netipx/workflows/Linux/badge.svg)](https://github.com/go4org/netipx/actions) [![Go Reference](https://pkg.go.dev/badge/go4.org/netipx.svg)](https://pkg.go.dev/go4.org/netipx) + +## What + +This is a package containing the bits of the old `inet.af/netaddr` package that didn't make it +into Go 1.18's `net/netip` standard library package. + +As background, see: + +* https://github.com/inetaf/netaddr/ (now deprecated) +* https://tailscale.com/blog/netaddr-new-ip-type-for-go/ - blog post about why the package came to be originally +* https://go.dev/doc/go1.18#netip - Go 1.18 release notes + +This package requires Go 1.18+ to use and complements the `net/netip`. + +## FAQ + +**Why's it no longer under `inet.af`?** Since that joke started, that +TLD is now under control of the Taliban. (Yes, we should've known +better. We'd even previously scolded people for relying on +questionable ccTLDs. Whoops.) + +**Will this stuff make it into the standard library?** [Maybe](https://github.com/golang/go/issues/53236). +We'll see. + + diff --git a/vendor/inet.af/netaddr/ipset.go b/vendor/go4.org/netipx/ipset.go similarity index 88% rename from vendor/inet.af/netaddr/ipset.go rename to vendor/go4.org/netipx/ipset.go index b448e25f..1d4d4502 100644 --- a/vendor/inet.af/netaddr/ipset.go +++ b/vendor/go4.org/netipx/ipset.go @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package netaddr +package netipx import ( "fmt" + "net/netip" "runtime" "sort" "strings" @@ -106,7 +107,7 @@ func (s *IPSetBuilder) normalize() { // f-------------t // f------t // out - min = append(min, IPRange{from: rin.from, to: rout.from.Prior()}) + min = append(min, IPRange{from: rin.from, to: AddrPrior(rout.from)}) // Adjust in[0], not ir, because we want to consider the // mutated range on the next iteration. in[0].from = rout.to.Next() @@ -136,7 +137,7 @@ func (s *IPSetBuilder) normalize() { // f------t // f------t // in - min = append(min, IPRange{from: rin.from, to: rout.from.Prior()}) + min = append(min, IPRange{from: rin.from, to: AddrPrior(rout.from)}) in = in[1:] if debug { debugf("merge out cuts end of in; append shortened in") @@ -181,8 +182,8 @@ func (s *IPSetBuilder) addError(msg string, args ...interface{}) { } // Add adds ip to s. -func (s *IPSetBuilder) Add(ip IP) { - if ip.IsZero() { +func (s *IPSetBuilder) Add(ip netip.Addr) { + if !ip.IsValid() { s.addError("Add(IP{})") return } @@ -190,11 +191,11 @@ func (s *IPSetBuilder) Add(ip IP) { } // AddPrefix adds all IPs in p to s. -func (s *IPSetBuilder) AddPrefix(p IPPrefix) { - if r := p.Range(); r.IsValid() { +func (s *IPSetBuilder) AddPrefix(p netip.Prefix) { + if r := RangeOfPrefix(p); r.IsValid() { s.AddRange(r) } else { - s.addError("AddPrefix(%v/%v)", p.IP(), p.Bits()) + s.addError("AddPrefix(%v/%v)", p.Addr(), p.Bits()) } } @@ -224,8 +225,8 @@ func (s *IPSetBuilder) AddSet(b *IPSet) { } // Remove removes ip from s. -func (s *IPSetBuilder) Remove(ip IP) { - if ip.IsZero() { +func (s *IPSetBuilder) Remove(ip netip.Addr) { + if !ip.IsValid() { s.addError("Remove(IP{})") } else { s.RemoveRange(IPRangeFrom(ip, ip)) @@ -233,11 +234,11 @@ func (s *IPSetBuilder) Remove(ip IP) { } // RemovePrefix removes all IPs in p from s. -func (s *IPSetBuilder) RemovePrefix(p IPPrefix) { - if r := p.Range(); r.IsValid() { +func (s *IPSetBuilder) RemovePrefix(p netip.Prefix) { + if r := RangeOfPrefix(p); r.IsValid() { s.RemoveRange(r) } else { - s.addError("RemovePrefix(%v/%v)", p.IP(), p.Bits()) + s.addError("RemovePrefix(%v/%v)", p.Addr(), p.Bits()) } } @@ -274,8 +275,8 @@ func (s *IPSetBuilder) Complement() { s.normalize() s.out = s.in s.in = []IPRange{ - IPPrefix{ip: IPv4(0, 0, 0, 0), bits: 0}.Range(), - IPPrefix{ip: IPv6Unspecified(), bits: 0}.Range(), + RangeOfPrefix(netip.PrefixFrom(netip.AddrFrom4([4]byte{}), 0)), + RangeOfPrefix(netip.PrefixFrom(netip.IPv6Unspecified(), 0)), } } @@ -340,8 +341,8 @@ func (s *IPSet) Ranges() []IPRange { // Prefixes returns the minimum and sorted set of IP prefixes // that covers s. -func (s *IPSet) Prefixes() []IPPrefix { - out := make([]IPPrefix, 0, len(s.rr)) +func (s *IPSet) Prefixes() []netip.Prefix { + out := make([]netip.Prefix, 0, len(s.rr)) for _, r := range s.rr { out = append(out, r.Prefixes()...) } @@ -365,8 +366,8 @@ func (s *IPSet) Equal(o *IPSet) bool { // Contains reports whether ip is in s. // If ip has an IPv6 zone, Contains returns false, // because IPSets do not track zones. -func (s *IPSet) Contains(ip IP) bool { - if ip.hasZone() { +func (s *IPSet) Contains(ip netip.Addr) bool { + if ip.Zone() != "" { return false } // TODO: data structure permitting more efficient lookups: @@ -392,8 +393,8 @@ func (s *IPSet) ContainsRange(r IPRange) bool { } // ContainsPrefix reports whether all IPs in p are in s. -func (s *IPSet) ContainsPrefix(p IPPrefix) bool { - return s.ContainsRange(p.Range()) +func (s *IPSet) ContainsPrefix(p netip.Prefix) bool { + return s.ContainsRange(RangeOfPrefix(p)) } // Overlaps reports whether any IP in b is also in s. @@ -421,8 +422,8 @@ func (s *IPSet) OverlapsRange(r IPRange) bool { } // OverlapsPrefix reports whether any IP in p is also in s. -func (s *IPSet) OverlapsPrefix(p IPPrefix) bool { - return s.OverlapsRange(p.Range()) +func (s *IPSet) OverlapsPrefix(p netip.Prefix) bool { + return s.OverlapsRange(RangeOfPrefix(p)) } // RemoveFreePrefix splits s into a Prefix of length bitLen and a new @@ -430,16 +431,16 @@ func (s *IPSet) OverlapsPrefix(p IPPrefix) bool { // // If no contiguous prefix of length bitLen exists in s, // RemoveFreePrefix returns ok=false. -func (s *IPSet) RemoveFreePrefix(bitLen uint8) (p IPPrefix, newSet *IPSet, ok bool) { - var bestFit IPPrefix +func (s *IPSet) RemoveFreePrefix(bitLen uint8) (p netip.Prefix, newSet *IPSet, ok bool) { + var bestFit netip.Prefix for _, r := range s.rr { for _, prefix := range r.Prefixes() { - if prefix.bits > bitLen { + if uint8(prefix.Bits()) > bitLen { continue } - if bestFit.ip.IsZero() || prefix.bits > bestFit.bits { + if !bestFit.Addr().IsValid() || prefix.Bits() > bestFit.Bits() { bestFit = prefix - if bestFit.bits == bitLen { + if uint8(bestFit.Bits()) == bitLen { // exact match, done. break } @@ -447,11 +448,11 @@ func (s *IPSet) RemoveFreePrefix(bitLen uint8) (p IPPrefix, newSet *IPSet, ok bo } } - if bestFit.ip.IsZero() { - return IPPrefix{}, s, false + if !bestFit.Addr().IsValid() { + return netip.Prefix{}, s, false } - prefix := IPPrefix{ip: bestFit.ip, bits: bitLen} + prefix := netip.PrefixFrom(bestFit.Addr(), int(bitLen)) var b IPSetBuilder b.AddSet(s) diff --git a/vendor/inet.af/netaddr/mask6.go b/vendor/go4.org/netipx/mask6.go similarity index 99% rename from vendor/inet.af/netaddr/mask6.go rename to vendor/go4.org/netipx/mask6.go index 72a20ede..fbcb8b8e 100644 --- a/vendor/inet.af/netaddr/mask6.go +++ b/vendor/go4.org/netipx/mask6.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 netaddr +package netipx // mask6 are bitmasks with the topmost n bits of a // 128-bit number, where n is the array index. diff --git a/vendor/go4.org/netipx/netipx.go b/vendor/go4.org/netipx/netipx.go new file mode 100644 index 00000000..d241fb38 --- /dev/null +++ b/vendor/go4.org/netipx/netipx.go @@ -0,0 +1,584 @@ +// Copyright 2020 The Inet.Af 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 netipx contains code and types that were left behind when +// the old inet.af/netaddr package moved to the standard library in Go +// 1.18 as net/netip. +package netipx // import "go4.org/netipx" + +import ( + "errors" + "fmt" + "math" + "net" + "net/netip" + "sort" + "strings" +) + +// FromStdIP returns an IP from the standard library's IP type. +// +// If std is invalid, ok is false. +// +// FromStdIP implicitly unmaps IPv6-mapped IPv4 addresses. That is, if +// len(std) == 16 and contains an IPv4 address, only the IPv4 part is +// returned, without the IPv6 wrapper. This is the common form returned by +// the standard library's ParseIP: https://play.golang.org/p/qdjylUkKWxl. +// To convert a standard library IP without the implicit unmapping, use +// netip.AddrFromSlice. +func FromStdIP(std net.IP) (ip netip.Addr, ok bool) { + ret, ok := netip.AddrFromSlice(std) + return ret.Unmap(), ok +} + +// MustFromStdIP is like FromStdIP, but it panics if std is invalid. +func MustFromStdIP(std net.IP) netip.Addr { + ret, ok := netip.AddrFromSlice(std) + if !ok { + panic("not a valid IP address") + } + return ret.Unmap() +} + +// FromStdIPRaw returns an IP from the standard library's IP type. +// If std is invalid, ok is false. +// Unlike FromStdIP, FromStdIPRaw does not do an implicit Unmap if +// len(std) == 16 and contains an IPv6-mapped IPv4 address. +// +// Deprecated: use netip.AddrFromSlice instead. +func FromStdIPRaw(std net.IP) (ip netip.Addr, ok bool) { + return netip.AddrFromSlice(std) +} + +// ParsePrefixOrAddr parses s as an IP address prefix or IP address. If s parses +// as an IP address prefix, its [net/netip.Prefix.Addr] is returned. The string +// s can be an IPv4 address ("192.0.2.1"), IPv6 address ("2001:db8::68"), IPv4 +// prefix ("192.0.2.1/32"), or IPv6 prefix ("2001:db:68/96"). +func ParsePrefixOrAddr(s string) (netip.Addr, error) { + // Factored out of netip.ParsePrefix to avoid allocating an empty netip.Prefix in case it's + // an address and not a prefix. + i := strings.LastIndexByte(s, '/') + if i < 0 { + return netip.ParseAddr(s) + } + prefix, err := netip.ParsePrefix(s) + return prefix.Addr(), err +} + +// AddrNext returns the IP following ip. +// If there is none, it returns the IP zero value. +// +// Deprecated: use netip.Addr.Next instead. +func AddrNext(ip netip.Addr) netip.Addr { + addr := u128From16(ip.As16()).addOne() + if ip.Is4() { + if uint32(addr.lo) == 0 { + // Overflowed. + return netip.Addr{} + } + return addr.IP4() + } else { + if addr.isZero() { + // Overflowed + return netip.Addr{} + } + return addr.IP6().WithZone(ip.Zone()) + } +} + +// AddrPrior returns the IP before ip. +// If there is none, it returns the IP zero value. +// +// Deprecated: use netip.Addr.Prev instead. +func AddrPrior(ip netip.Addr) netip.Addr { + addr := u128From16(ip.As16()) + if ip.Is4() { + if uint32(addr.lo) == 0 { + return netip.Addr{} + } + return addr.subOne().IP4() + } else { + if addr.isZero() { + return netip.Addr{} + } + return addr.subOne().IP6().WithZone(ip.Zone()) + } +} + +// FromStdAddr maps the components of a standard library TCPAddr or +// UDPAddr into an IPPort. +func FromStdAddr(stdIP net.IP, port int, zone string) (_ netip.AddrPort, ok bool) { + ip, ok := FromStdIP(stdIP) + if !ok || port < 0 || port > math.MaxUint16 { + return netip.AddrPort{}, false + } + ip = ip.Unmap() + if zone != "" { + if ip.Is4() { + ok = false + return + } + ip = ip.WithZone(zone) + } + return netip.AddrPortFrom(ip, uint16(port)), true +} + +// FromStdIPNet returns an netip.Prefix from the standard library's IPNet type. +// If std is invalid, ok is false. +func FromStdIPNet(std *net.IPNet) (prefix netip.Prefix, ok bool) { + ip, ok := FromStdIP(std.IP) + if !ok { + return netip.Prefix{}, false + } + + if l := len(std.Mask); l != net.IPv4len && l != net.IPv6len { + // Invalid mask. + return netip.Prefix{}, false + } + + ones, bits := std.Mask.Size() + if ones == 0 && bits == 0 { + // IPPrefix does not support non-contiguous masks. + return netip.Prefix{}, false + } + + return netip.PrefixFrom(ip, ones), true +} + +// RangeOfPrefix returns the inclusive range of IPs that p covers. +// +// If p is zero or otherwise invalid, Range returns the zero value. +func RangeOfPrefix(p netip.Prefix) IPRange { + p = p.Masked() + if !p.IsValid() { + return IPRange{} + } + return IPRangeFrom(p.Addr(), PrefixLastIP(p)) +} + +// PrefixIPNet returns the net.IPNet representation of an netip.Prefix. +// The returned value is always non-nil. +// Any zone identifier is dropped in the conversion. +func PrefixIPNet(p netip.Prefix) *net.IPNet { + if !p.IsValid() { + return &net.IPNet{} + } + return &net.IPNet{ + IP: p.Addr().AsSlice(), + Mask: net.CIDRMask(p.Bits(), p.Addr().BitLen()), + } +} + +// AddrIPNet returns the net.IPNet representation of an netip.Addr +// with a mask corresponding to the addresses's bit length. +// The returned value is always non-nil. +// Any zone identifier is dropped in the conversion. +func AddrIPNet(addr netip.Addr) *net.IPNet { + if !addr.IsValid() { + return &net.IPNet{} + } + return &net.IPNet{ + IP: addr.AsSlice(), + Mask: net.CIDRMask(addr.BitLen(), addr.BitLen()), + } +} + +// PrefixLastIP returns the last IP in the prefix. +func PrefixLastIP(p netip.Prefix) netip.Addr { + if !p.IsValid() { + return netip.Addr{} + } + a16 := p.Addr().As16() + var off uint8 + var bits uint8 = 128 + if p.Addr().Is4() { + off = 12 + bits = 32 + } + for b := uint8(p.Bits()); b < bits; b++ { + byteNum, bitInByte := b/8, 7-(b%8) + a16[off+byteNum] |= 1 << uint(bitInByte) + } + if p.Addr().Is4() { + return netip.AddrFrom16(a16).Unmap() + } else { + return netip.AddrFrom16(a16) // doesn't unmap + } +} + +// IPRange represents an inclusive range of IP addresses +// from the same address family. +// +// The From and To IPs are inclusive bounds, with both included in the +// range. +// +// To be valid, the From and To values must be non-zero, have matching +// address families (IPv4 vs IPv6), and From must be less than or equal to To. +// IPv6 zones are stripped out and ignored. +// An invalid range may be ignored. +type IPRange struct { + // from is the initial IP address in the range. + from netip.Addr + + // to is the final IP address in the range. + to netip.Addr +} + +// IPRangeFrom returns an IPRange from from to to. +// It does not allocate. +func IPRangeFrom(from, to netip.Addr) IPRange { + return IPRange{ + from: from.WithZone(""), + to: to.WithZone(""), + } +} + +// From returns the lower bound of r. +func (r IPRange) From() netip.Addr { return r.from } + +// To returns the upper bound of r. +func (r IPRange) To() netip.Addr { return r.to } + +// ParseIPRange parses a range out of two IPs separated by a hyphen. +// +// It returns an error if the range is not valid. +func ParseIPRange(s string) (IPRange, error) { + var r IPRange + h := strings.IndexByte(s, '-') + if h == -1 { + return r, fmt.Errorf("no hyphen in range %q", s) + } + from, to := s[:h], s[h+1:] + var err error + r.from, err = netip.ParseAddr(from) + if err != nil { + return r, fmt.Errorf("invalid From IP %q in range %q", from, s) + } + r.from = r.from.WithZone("") + r.to, err = netip.ParseAddr(to) + if err != nil { + return r, fmt.Errorf("invalid To IP %q in range %q", to, s) + } + r.to = r.to.WithZone("") + if !r.IsValid() { + return r, fmt.Errorf("range %v to %v not valid", r.from, r.to) + } + return r, nil +} + +// MustParseIPRange calls ParseIPRange(s) and panics on error. +// It is intended for use in tests with hard-coded strings. +func MustParseIPRange(s string) IPRange { + r, err := ParseIPRange(s) + if err != nil { + panic(err) + } + return r +} + +// String returns a string representation of the range. +// +// For a valid range, the form is "From-To" with a single hyphen +// separating the IPs, the same format recognized by +// ParseIPRange. +func (r IPRange) String() string { + if r.IsValid() { + return fmt.Sprintf("%s-%s", r.from, r.to) + } + if !r.from.IsValid() || !r.to.IsValid() { + return "zero IPRange" + } + return "invalid IPRange" +} + +// AppendTo appends a text encoding of r, +// as generated by MarshalText, +// to b and returns the extended buffer. +func (r IPRange) AppendTo(b []byte) []byte { + if r.IsZero() { + return b + } + b = r.from.AppendTo(b) + b = append(b, '-') + b = r.to.AppendTo(b) + return b +} + +// MarshalText implements the encoding.TextMarshaler interface, +// The encoding is the same as returned by String, with one exception: +// If ip is the zero value, the encoding is the empty string. +func (r IPRange) MarshalText() ([]byte, error) { + if r.IsZero() { + return []byte(""), nil + } + var max int + if r.from.Is4() { + max = len("255.255.255.255-255.255.255.255") + } else { + max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") + } + b := make([]byte, 0, max) + return r.AppendTo(b), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The IP range is expected in a form accepted by ParseIPRange. +// It returns an error if *r is not the IPRange zero value. +func (r *IPRange) UnmarshalText(text []byte) error { + if *r != (IPRange{}) { + return errors.New("refusing to Unmarshal into non-zero IPRange") + } + if len(text) == 0 { + return nil + } + var err error + *r, err = ParseIPRange(string(text)) + return err +} + +// IsZero reports whether r is the zero value of the IPRange type. +func (r IPRange) IsZero() bool { + return r == IPRange{} +} + +// IsValid reports whether r.From() and r.To() are both non-zero and +// obey the documented requirements: address families match, and From +// is less than or equal to To. +func (r IPRange) IsValid() bool { + return r.from.IsValid() && + r.from.BitLen() == r.to.BitLen() && + r.from.Zone() == r.to.Zone() && + !r.to.Less(r.from) +} + +// Valid reports whether r.From() and r.To() are both non-zero and +// obey the documented requirements: address families match, and From +// is less than or equal to To. +// +// Deprecated: use the correctly named and identical IsValid method instead. +func (r IPRange) Valid() bool { return r.IsValid() } + +// Contains reports whether the range r includes addr. +// +// An invalid range always reports false. +// +// If ip has an IPv6 zone, Contains returns false, +// because IPPrefixes strip zones. +func (r IPRange) Contains(addr netip.Addr) bool { + return r.IsValid() && addr.Zone() == "" && r.contains(addr) +} + +// contains is like Contains, but without the validity check. +// addr must not have a zone. +func (r IPRange) contains(addr netip.Addr) bool { + return r.from.Compare(addr) <= 0 && r.to.Compare(addr) >= 0 +} + +// less reports whether r is "before" other. It is before if r.From() +// is before other.From(). If they're equal, then the larger range +// (higher To()) comes first. +func (r IPRange) less(other IPRange) bool { + if cmp := r.from.Compare(other.from); cmp != 0 { + return cmp < 0 + } + return other.to.Less(r.to) +} + +// entirelyBefore returns whether r lies entirely before other in IP +// space. +func (r IPRange) entirelyBefore(other IPRange) bool { + return r.to.Less(other.from) +} + +func lessOrEq(ip, ip2 netip.Addr) bool { return ip.Compare(ip2) <= 0 } + +// entirelyWithin returns whether r is entirely contained within +// other. +func (r IPRange) coveredBy(other IPRange) bool { + return lessOrEq(other.from, r.from) && lessOrEq(r.to, other.to) +} + +// inMiddleOf returns whether r is inside other, but not touching the +// edges of other. +func (r IPRange) inMiddleOf(other IPRange) bool { + return other.from.Less(r.from) && r.to.Less(other.to) +} + +// overlapsStartOf returns whether r entirely overlaps the start of +// other, but not all of other. +func (r IPRange) overlapsStartOf(other IPRange) bool { + return lessOrEq(r.from, other.from) && r.to.Less(other.to) +} + +// overlapsEndOf returns whether r entirely overlaps the end of +// other, but not all of other. +func (r IPRange) overlapsEndOf(other IPRange) bool { + return other.from.Less(r.from) && lessOrEq(other.to, r.to) +} + +// mergeIPRanges returns the minimum and sorted set of IP ranges that +// cover r. +func mergeIPRanges(rr []IPRange) (out []IPRange, valid bool) { + // Always return a copy of r, to avoid aliasing slice memory in + // the caller. + switch len(rr) { + case 0: + return nil, true + case 1: + return []IPRange{rr[0]}, true + } + + sort.Slice(rr, func(i, j int) bool { return rr[i].less(rr[j]) }) + out = make([]IPRange, 1, len(rr)) + out[0] = rr[0] + for _, r := range rr[1:] { + prev := &out[len(out)-1] + switch { + case !r.IsValid(): + // Invalid ranges make no sense to merge, refuse to + // perform. + return nil, false + case prev.to.Next() == r.from: + // prev and r touch, merge them. + // + // prev r + // f------tf-----t + prev.to = r.to + case prev.to.Less(r.from): + // No overlap and not adjacent (per previous case), no + // merging possible. + // + // prev r + // f------t f-----t + out = append(out, r) + case prev.to.Less(r.to): + // Partial overlap, update prev + // + // prev + // f------t + // f-----t + // r + prev.to = r.to + default: + // r entirely contained in prev, nothing to do. + // + // prev + // f--------t + // f-----t + // r + } + } + return out, true +} + +// Overlaps reports whether p and o overlap at all. +// +// If p and o are of different address families or either are invalid, +// it reports false. +func (r IPRange) Overlaps(o IPRange) bool { + return r.IsValid() && + o.IsValid() && + r.from.Compare(o.to) <= 0 && + o.from.Compare(r.to) <= 0 +} + +// prefixMaker returns a address-family-corrected IPPrefix from a and bits, +// where the input bits is always in the IPv6-mapped form for IPv4 addresses. +type prefixMaker func(a uint128, bits uint8) netip.Prefix + +// Prefixes returns the set of IPPrefix entries that covers r. +// +// If either of r's bounds are invalid, in the wrong order, or if +// they're of different address families, then Prefixes returns nil. +// +// Prefixes necessarily allocates. See AppendPrefixes for a version that uses +// memory you provide. +func (r IPRange) Prefixes() []netip.Prefix { + return r.AppendPrefixes(nil) +} + +// AppendPrefixes is an append version of IPRange.Prefixes. It appends +// the netip.Prefix entries that cover r to dst. +func (r IPRange) AppendPrefixes(dst []netip.Prefix) []netip.Prefix { + if !r.IsValid() { + return nil + } + return appendRangePrefixes(dst, r.prefixFrom128AndBits, u128From16(r.from.As16()), u128From16(r.to.As16())) +} + +func (r IPRange) prefixFrom128AndBits(a uint128, bits uint8) netip.Prefix { + var ip netip.Addr + if r.from.Is4() { + bits -= 12 * 8 + ip = a.IP4() + } else { + ip = a.IP6() + } + return netip.PrefixFrom(ip, int(bits)) +} + +// aZeroBSet is whether, after the common bits, a is all zero bits and +// b is all set (one) bits. +func comparePrefixes(a, b uint128) (common uint8, aZeroBSet bool) { + common = a.commonPrefixLen(b) + + // See whether a and b, after their common shared bits, end + // in all zero bits or all one bits, respectively. + if common == 128 { + return common, true + } + + m := mask6[common] + return common, (a.xor(a.and(m)).isZero() && + b.or(m) == uint128{^uint64(0), ^uint64(0)}) +} + +// Prefix returns r as an IPPrefix, if it can be presented exactly as such. +// If r is not valid or is not exactly equal to one prefix, ok is false. +func (r IPRange) Prefix() (p netip.Prefix, ok bool) { + if !r.IsValid() { + return + } + from128 := u128From16(r.from.As16()) + to128 := u128From16(r.to.As16()) + if common, ok := comparePrefixes(from128, to128); ok { + return r.prefixFrom128AndBits(from128, common), true + } + return +} + +func appendRangePrefixes(dst []netip.Prefix, makePrefix prefixMaker, a, b uint128) []netip.Prefix { + common, ok := comparePrefixes(a, b) + if ok { + // a to b represents a whole range, like 10.50.0.0/16. + // (a being 10.50.0.0 and b being 10.50.255.255) + return append(dst, makePrefix(a, common)) + } + // Otherwise recursively do both halves. + dst = appendRangePrefixes(dst, makePrefix, a, a.bitsSetFrom(common+1)) + dst = appendRangePrefixes(dst, makePrefix, b.bitsClearedFrom(common+1), b) + return dst +} + +// ComparePrefix is a compare function (returning -1, 0 or 1) +// sorting prefixes first by address family (IPv4 before IPv6), +// then by prefix length (smaller prefixes first), then by +// address. +func ComparePrefix(a, b netip.Prefix) int { + aa, ba := a.Addr(), b.Addr() + if al, bl := aa.BitLen(), ba.BitLen(); al != bl { + if al < bl { + return -1 + } + return 1 + } + ab, bb := a.Bits(), b.Bits() + if ab != bb { + if ab < bb { + return -1 + } + return 1 + } + return aa.Compare(ba) +} diff --git a/vendor/inet.af/netaddr/uint128.go b/vendor/go4.org/netipx/uint128.go similarity index 77% rename from vendor/inet.af/netaddr/uint128.go rename to vendor/go4.org/netipx/uint128.go index 2ba93f31..f59ea23c 100644 --- a/vendor/inet.af/netaddr/uint128.go +++ b/vendor/go4.org/netipx/uint128.go @@ -2,9 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package netaddr +package netipx -import "math/bits" +import ( + "encoding/binary" + "math/bits" + "net/netip" +) // uint128 represents a uint128 using two uint64s. // @@ -15,6 +19,26 @@ type uint128 struct { lo uint64 } +func u128From16(a [16]byte) uint128 { + return uint128{ + binary.BigEndian.Uint64(a[:8]), + binary.BigEndian.Uint64(a[8:]), + } +} + +func (u uint128) IP6() netip.Addr { + var a [16]byte + binary.BigEndian.PutUint64(a[:8], u.hi) + binary.BigEndian.PutUint64(a[8:], u.lo) + return netip.AddrFrom16(a) +} + +func (u uint128) IP4() netip.Addr { + var a [8]byte + binary.BigEndian.PutUint64(a[:], u.lo) + return netip.AddrFrom4([4]byte{a[4], a[5], a[6], a[7]}) +} + // isZero reports whether u == 0. // // It's faster than u == (uint128{}) because the compiler (as of Go @@ -65,9 +89,9 @@ func (u uint128) commonPrefixLen(v uint128) (n uint8) { return } -func (u *uint128) halves() [2]*uint64 { - return [2]*uint64{&u.hi, &u.lo} -} +// func (u *uint128) halves() [2]*uint64 { +// return [2]*uint64{&u.hi, &u.lo} +// } // bitsSetFrom returns a copy of u with the given bit // and all subsequent ones set. diff --git a/vendor/go4.org/unsafe/assume-no-moving-gc/LICENSE b/vendor/go4.org/unsafe/assume-no-moving-gc/LICENSE deleted file mode 100644 index b0ab8921..00000000 --- a/vendor/go4.org/unsafe/assume-no-moving-gc/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2020, Brad Fitzpatrick -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. - -3. Neither the name of the copyright holder 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 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/go4.org/unsafe/assume-no-moving-gc/README.md b/vendor/go4.org/unsafe/assume-no-moving-gc/README.md deleted file mode 100644 index 920fc9dd..00000000 --- a/vendor/go4.org/unsafe/assume-no-moving-gc/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# go4.org/unsafe/assume-no-moving-gc - -If your Go package wants to declare that it plays `unsafe` games that only -work if the Go runtime's garbage collector is not a moving collector, then add: - -```go -import _ "go4.org/unsafe/assume-no-moving-gc" -``` - -Then your program will explode if that's no longer the case. (Users can override -the explosion with a scary sounding environment variable.) - -This also gives us a way to find all the really gross unsafe packages. diff --git a/vendor/go4.org/unsafe/assume-no-moving-gc/assume-no-moving-gc.go b/vendor/go4.org/unsafe/assume-no-moving-gc/assume-no-moving-gc.go deleted file mode 100644 index 60561d05..00000000 --- a/vendor/go4.org/unsafe/assume-no-moving-gc/assume-no-moving-gc.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2020 Brad Fitzpatrick. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package go4.org/unsafe/assume-no-moving-gc exists so you can depend -// on it from unsafe code that wants to declare that it assumes that -// the Go runtime does not using a moving garbage collector. Specifically, -// it asserts that the caller is playing stupid games with the addresses -// of heap-allocated values. It says nothing about values that Go's escape -// analysis keeps on the stack. Ensuring things aren't stack-allocated -// is the caller's responsibility. -// -// This package is then updated as needed for new Go versions when -// that is still the case and explodes at runtime with a failure -// otherwise, with the idea that it's better to not start at all than -// to silently corrupt your data at runtime. -// -// To use: -// -// import _ "go4.org/unsafe/assume-no-moving-gc" -// -// There is no API. -// -// As of Go 1.21, this package asks the Go runtime whether it can move -// heap objects around. If you get an error on versions prior to that, -// go get go4.org/unsafe/assume-no-moving-gc@latest and things will -// work. -// -// The GitHub repo is at https://github.com/go4org/unsafe-assume-no-moving-gc -package assume_no_moving_gc - -const env = "ASSUME_NO_MOVING_GC_UNSAFE" diff --git a/vendor/go4.org/unsafe/assume-no-moving-gc/check.go b/vendor/go4.org/unsafe/assume-no-moving-gc/check.go deleted file mode 100644 index a2fbf465..00000000 --- a/vendor/go4.org/unsafe/assume-no-moving-gc/check.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020 Brad Fitzpatrick. 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 -// +build go1.21 - -package assume_no_moving_gc - -import ( - "os" - _ "unsafe" -) - -//go:linkname heapObjectsCanMove runtime.heapObjectsCanMove -func heapObjectsCanMove() bool - -func init() { - if !heapObjectsCanMove() { - // The unsafe assumptions made by the package - // importing this package still hold. All's good. (at - // least unless they made other assumption this - // package doesn't concern itself with) - return - } - if os.Getenv(env) == "play-with-fire" { - return - } - panic(` -Something in this program imports go4.org/unsafe/assume-no-moving-gc to -declare that it assumes a non-moving garbage collector, but the version -of Go you're using declares that its heap objects can now move around. -This program is no longer safe. You should update your packages which import -go4.org/unsafe/assume-no-moving-gc. To risk it and bypass this check, set -ASSUME_NO_MOVING_GC_UNSAFE=play-with-fire and cross your fingers.`) -} diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE new file mode 100644 index 00000000..6a66aea5 --- /dev/null +++ b/vendor/golang.org/x/exp/LICENSE @@ -0,0 +1,27 @@ +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/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS new file mode 100644 index 00000000..73309904 --- /dev/null +++ b/vendor/golang.org/x/exp/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go new file mode 100644 index 00000000..2c033dff --- /dev/null +++ b/vendor/golang.org/x/exp/constraints/constraints.go @@ -0,0 +1,50 @@ +// 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 constraints defines a set of useful constraints to be used +// with type parameters. +package constraints + +// Signed is a constraint that permits any signed integer type. +// If future releases of Go add new predeclared signed integer types, +// this constraint will be modified to include them. +type Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Unsigned is a constraint that permits any unsigned integer type. +// If future releases of Go add new predeclared unsigned integer types, +// this constraint will be modified to include them. +type Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +// Integer is a constraint that permits any integer type. +// If future releases of Go add new predeclared integer types, +// this constraint will be modified to include them. +type Integer interface { + Signed | Unsigned +} + +// Float is a constraint that permits any floating-point type. +// If future releases of Go add new predeclared floating-point types, +// this constraint will be modified to include them. +type Float interface { + ~float32 | ~float64 +} + +// Complex is a constraint that permits any complex numeric type. +// If future releases of Go add new predeclared complex numeric types, +// this constraint will be modified to include them. +type Complex interface { + ~complex64 | ~complex128 +} + +// Ordered is a constraint that permits any ordered type: any type +// that supports the operators < <= >= >. +// If future releases of Go add new ordered types, +// this constraint will be modified to include them. +type Ordered interface { + Integer | Float | ~string +} diff --git a/vendor/golang.org/x/exp/slices/cmp.go b/vendor/golang.org/x/exp/slices/cmp.go new file mode 100644 index 00000000..fbf1934a --- /dev/null +++ b/vendor/golang.org/x/exp/slices/cmp.go @@ -0,0 +1,44 @@ +// 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 slices + +import "golang.org/x/exp/constraints" + +// min is a version of the predeclared function from the Go 1.21 release. +func min[T constraints.Ordered](a, b T) T { + if a < b || isNaN(a) { + return a + } + return b +} + +// max is a version of the predeclared function from the Go 1.21 release. +func max[T constraints.Ordered](a, b T) T { + if a > b || isNaN(a) { + return a + } + return b +} + +// cmpLess is a copy of cmp.Less from the Go 1.21 release. +func cmpLess[T constraints.Ordered](x, y T) bool { + return (isNaN(x) && !isNaN(y)) || x < y +} + +// cmpCompare is a copy of cmp.Compare from the Go 1.21 release. +func cmpCompare[T constraints.Ordered](x, y T) int { + xNaN := isNaN(x) + yNaN := isNaN(y) + if xNaN && yNaN { + return 0 + } + if xNaN || x < y { + return -1 + } + if yNaN || x > y { + return +1 + } + return 0 +} diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go new file mode 100644 index 00000000..5e8158bb --- /dev/null +++ b/vendor/golang.org/x/exp/slices/slices.go @@ -0,0 +1,499 @@ +// 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 slices defines various functions useful with slices of any type. +package slices + +import ( + "unsafe" + + "golang.org/x/exp/constraints" +) + +// Equal reports whether two slices are equal: the same length and all +// elements equal. If the lengths are different, Equal returns false. +// Otherwise, the elements are compared in increasing index order, and the +// comparison stops at the first unequal pair. +// Floating point NaNs are not considered equal. +func Equal[S ~[]E, E comparable](s1, s2 S) bool { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + if s1[i] != s2[i] { + return false + } + } + return true +} + +// EqualFunc reports whether two slices are equal using an equality +// function on each pair of elements. If the lengths are different, +// EqualFunc returns false. Otherwise, the elements are compared in +// increasing index order, and the comparison stops at the first index +// for which eq returns false. +func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if !eq(v1, v2) { + return false + } + } + return true +} + +// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair +// of elements. The elements are compared sequentially, starting at index 0, +// until one element is not equal to the other. +// The result of comparing the first non-matching elements is returned. +// If both slices are equal until one of them ends, the shorter slice is +// considered less than the longer one. +// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2. +func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int { + for i, v1 := range s1 { + if i >= len(s2) { + return +1 + } + v2 := s2[i] + if c := cmpCompare(v1, v2); c != 0 { + return c + } + } + if len(s1) < len(s2) { + return -1 + } + return 0 +} + +// CompareFunc is like [Compare] but uses a custom comparison function on each +// pair of elements. +// The result is the first non-zero result of cmp; if cmp always +// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2), +// and +1 if len(s1) > len(s2). +func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int { + for i, v1 := range s1 { + if i >= len(s2) { + return +1 + } + v2 := s2[i] + if c := cmp(v1, v2); c != 0 { + return c + } + } + if len(s1) < len(s2) { + return -1 + } + return 0 +} + +// Index returns the index of the first occurrence of v in s, +// or -1 if not present. +func Index[S ~[]E, E comparable](s S, v E) int { + for i := range s { + if v == s[i] { + return i + } + } + return -1 +} + +// IndexFunc returns the first index i satisfying f(s[i]), +// or -1 if none do. +func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int { + for i := range s { + if f(s[i]) { + return i + } + } + return -1 +} + +// Contains reports whether v is present in s. +func Contains[S ~[]E, E comparable](s S, v E) bool { + return Index(s, v) >= 0 +} + +// ContainsFunc reports whether at least one +// element e of s satisfies f(e). +func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool { + return IndexFunc(s, f) >= 0 +} + +// Insert inserts the values v... into s at index i, +// returning the modified slice. +// The elements at s[i:] are shifted up to make room. +// In the returned slice r, r[i] == v[0], +// and r[i+len(v)] == value originally at r[i]. +// Insert panics if i is out of range. +// This function is O(len(s) + len(v)). +func Insert[S ~[]E, E any](s S, i int, v ...E) S { + m := len(v) + if m == 0 { + return s + } + n := len(s) + if i == n { + return append(s, v...) + } + if n+m > cap(s) { + // Use append rather than make so that we bump the size of + // the slice up to the next storage class. + // This is what Grow does but we don't call Grow because + // that might copy the values twice. + s2 := append(s[:i], make(S, n+m-i)...) + copy(s2[i:], v) + copy(s2[i+m:], s[i:]) + return s2 + } + s = s[:n+m] + + // before: + // s: aaaaaaaabbbbccccccccdddd + // ^ ^ ^ ^ + // i i+m n n+m + // after: + // s: aaaaaaaavvvvbbbbcccccccc + // ^ ^ ^ ^ + // i i+m n n+m + // + // a are the values that don't move in s. + // v are the values copied in from v. + // b and c are the values from s that are shifted up in index. + // d are the values that get overwritten, never to be seen again. + + if !overlaps(v, s[i+m:]) { + // Easy case - v does not overlap either the c or d regions. + // (It might be in some of a or b, or elsewhere entirely.) + // The data we copy up doesn't write to v at all, so just do it. + + copy(s[i+m:], s[i:]) + + // Now we have + // s: aaaaaaaabbbbbbbbcccccccc + // ^ ^ ^ ^ + // i i+m n n+m + // Note the b values are duplicated. + + copy(s[i:], v) + + // Now we have + // s: aaaaaaaavvvvbbbbcccccccc + // ^ ^ ^ ^ + // i i+m n n+m + // That's the result we want. + return s + } + + // The hard case - v overlaps c or d. We can't just shift up + // the data because we'd move or clobber the values we're trying + // to insert. + // So instead, write v on top of d, then rotate. + copy(s[n:], v) + + // Now we have + // s: aaaaaaaabbbbccccccccvvvv + // ^ ^ ^ ^ + // i i+m n n+m + + rotateRight(s[i:], m) + + // Now we have + // s: aaaaaaaavvvvbbbbcccccccc + // ^ ^ ^ ^ + // i i+m n n+m + // That's the result we want. + return s +} + +// Delete removes the elements s[i:j] from s, returning the modified slice. +// Delete panics if s[i:j] is not a valid slice of s. +// Delete is O(len(s)-j), so if many items must be deleted, it is better to +// make a single call deleting them all together than to delete one at a time. +// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those +// elements contain pointers you might consider zeroing those elements so that +// objects they reference can be garbage collected. +func Delete[S ~[]E, E any](s S, i, j int) S { + _ = s[i:j] // bounds check + + return append(s[:i], s[j:]...) +} + +// DeleteFunc removes any elements from s for which del returns true, +// returning the modified slice. +// When DeleteFunc removes m elements, it might not modify the elements +// s[len(s)-m:len(s)]. If those elements contain pointers you might consider +// zeroing those elements so that objects they reference can be garbage +// collected. +func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S { + i := IndexFunc(s, del) + if i == -1 { + return s + } + // Don't start copying elements until we find one to delete. + for j := i + 1; j < len(s); j++ { + if v := s[j]; !del(v) { + s[i] = v + i++ + } + } + return s[:i] +} + +// Replace replaces the elements s[i:j] by the given v, and returns the +// modified slice. Replace panics if s[i:j] is not a valid slice of s. +func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { + _ = s[i:j] // verify that i:j is a valid subslice + + if i == j { + return Insert(s, i, v...) + } + if j == len(s) { + return append(s[:i], v...) + } + + tot := len(s[:i]) + len(v) + len(s[j:]) + if tot > cap(s) { + // Too big to fit, allocate and copy over. + s2 := append(s[:i], make(S, tot-i)...) // See Insert + copy(s2[i:], v) + copy(s2[i+len(v):], s[j:]) + return s2 + } + + r := s[:tot] + + if i+len(v) <= j { + // Easy, as v fits in the deleted portion. + copy(r[i:], v) + if i+len(v) != j { + copy(r[i+len(v):], s[j:]) + } + return r + } + + // We are expanding (v is bigger than j-i). + // The situation is something like this: + // (example has i=4,j=8,len(s)=16,len(v)=6) + // s: aaaaxxxxbbbbbbbbyy + // ^ ^ ^ ^ + // i j len(s) tot + // a: prefix of s + // x: deleted range + // b: more of s + // y: area to expand into + + if !overlaps(r[i+len(v):], v) { + // Easy, as v is not clobbered by the first copy. + copy(r[i+len(v):], s[j:]) + copy(r[i:], v) + return r + } + + // This is a situation where we don't have a single place to which + // we can copy v. Parts of it need to go to two different places. + // We want to copy the prefix of v into y and the suffix into x, then + // rotate |y| spots to the right. + // + // v[2:] v[:2] + // | | + // s: aaaavvvvbbbbbbbbvv + // ^ ^ ^ ^ + // i j len(s) tot + // + // If either of those two destinations don't alias v, then we're good. + y := len(v) - (j - i) // length of y portion + + if !overlaps(r[i:j], v) { + copy(r[i:j], v[y:]) + copy(r[len(s):], v[:y]) + rotateRight(r[i:], y) + return r + } + if !overlaps(r[len(s):], v) { + copy(r[len(s):], v[:y]) + copy(r[i:j], v[y:]) + rotateRight(r[i:], y) + return r + } + + // Now we know that v overlaps both x and y. + // That means that the entirety of b is *inside* v. + // So we don't need to preserve b at all; instead we + // can copy v first, then copy the b part of v out of + // v to the right destination. + k := startIdx(v, s[j:]) + copy(r[i:], v) + copy(r[i+len(v):], r[i+k:]) + return r +} + +// Clone returns a copy of the slice. +// The elements are copied using assignment, so this is a shallow clone. +func Clone[S ~[]E, E any](s S) S { + // Preserve nil in case it matters. + if s == nil { + return nil + } + return append(S([]E{}), s...) +} + +// 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 and returns the modified slice, +// which may have a smaller length. +// When Compact discards m elements in total, it might not modify the elements +// s[len(s)-m:len(s)]. If those elements contain pointers you might consider +// zeroing those elements so that objects they reference can be garbage collected. +func Compact[S ~[]E, E comparable](s S) S { + if len(s) < 2 { + return s + } + i := 1 + for k := 1; k < len(s); k++ { + if s[k] != s[k-1] { + if i != k { + s[i] = s[k] + } + i++ + } + } + return s[:i] +} + +// CompactFunc is like [Compact] but uses an equality function to compare elements. +// For runs of elements that compare equal, CompactFunc keeps the first one. +func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { + if len(s) < 2 { + return s + } + i := 1 + for k := 1; k < len(s); k++ { + if !eq(s[k], s[k-1]) { + if i != k { + s[i] = s[k] + } + i++ + } + } + return s[:i] +} + +// Grow increases the slice's capacity, if necessary, to guarantee space for +// another n elements. After Grow(n), at least n elements can be appended +// to the slice without another allocation. If n is negative or too large to +// allocate the memory, Grow panics. +func Grow[S ~[]E, E any](s S, n int) S { + if n < 0 { + panic("cannot be negative") + } + if n -= cap(s) - len(s); n > 0 { + // TODO(https://go.dev/issue/53888): Make using []E instead of S + // to workaround a compiler bug where the runtime.growslice optimization + // does not take effect. Revert when the compiler is fixed. + s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)] + } + return s +} + +// Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. +func Clip[S ~[]E, E any](s S) S { + return s[:len(s):len(s)] +} + +// Rotation algorithm explanation: +// +// rotate left by 2 +// start with +// 0123456789 +// split up like this +// 01 234567 89 +// swap first 2 and last 2 +// 89 234567 01 +// join first parts +// 89234567 01 +// recursively rotate first left part by 2 +// 23456789 01 +// join at the end +// 2345678901 +// +// rotate left by 8 +// start with +// 0123456789 +// split up like this +// 01 234567 89 +// swap first 2 and last 2 +// 89 234567 01 +// join last parts +// 89 23456701 +// recursively rotate second part left by 6 +// 89 01234567 +// join at the end +// 8901234567 + +// TODO: There are other rotate algorithms. +// This algorithm has the desirable property that it moves each element exactly twice. +// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes. +// The follow-cycles algorithm can be 1-write but it is not very cache friendly. + +// rotateLeft rotates b left by n spaces. +// s_final[i] = s_orig[i+r], wrapping around. +func rotateLeft[E any](s []E, r int) { + for r != 0 && r != len(s) { + if r*2 <= len(s) { + swap(s[:r], s[len(s)-r:]) + s = s[:len(s)-r] + } else { + swap(s[:len(s)-r], s[r:]) + s, r = s[len(s)-r:], r*2-len(s) + } + } +} +func rotateRight[E any](s []E, r int) { + rotateLeft(s, len(s)-r) +} + +// swap swaps the contents of x and y. x and y must be equal length and disjoint. +func swap[E any](x, y []E) { + for i := 0; i < len(x); i++ { + x[i], y[i] = y[i], x[i] + } +} + +// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap. +func overlaps[E any](a, b []E) bool { + if len(a) == 0 || len(b) == 0 { + return false + } + elemSize := unsafe.Sizeof(a[0]) + if elemSize == 0 { + return false + } + // TODO: use a runtime/unsafe facility once one becomes available. See issue 12445. + // Also see crypto/internal/alias/alias.go:AnyOverlap + return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) && + uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1) +} + +// startIdx returns the index in haystack where the needle starts. +// prerequisite: the needle must be aliased entirely inside the haystack. +func startIdx[E any](haystack, needle []E) int { + p := &needle[0] + for i := range haystack { + if p == &haystack[i] { + return i + } + } + // TODO: what if the overlap is by a non-integral number of Es? + panic("needle not found") +} + +// Reverse reverses the elements of the slice in place. +func Reverse[S ~[]E, E any](s S) { + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } +} diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go new file mode 100644 index 00000000..b67897f7 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/sort.go @@ -0,0 +1,195 @@ +// 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:generate go run $GOROOT/src/sort/gen_sort_variants.go -exp + +package slices + +import ( + "math/bits" + + "golang.org/x/exp/constraints" +) + +// Sort sorts a slice of any ordered type in ascending order. +// When sorting floating-point numbers, NaNs are ordered before other values. +func Sort[S ~[]E, E constraints.Ordered](x S) { + n := len(x) + pdqsortOrdered(x, 0, n, bits.Len(uint(n))) +} + +// SortFunc sorts the slice x in ascending order as determined by the cmp +// function. This sort is not guaranteed to be stable. +// cmp(a, b) should return a negative number when a < b, a positive number when +// a > b and zero when a == b. +// +// SortFunc requires that cmp is a strict weak ordering. +// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. +func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { + n := len(x) + pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp) +} + +// SortStableFunc sorts the slice x while keeping the original order of equal +// elements, using cmp to compare elements in the same way as [SortFunc]. +func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { + stableCmpFunc(x, len(x), cmp) +} + +// IsSorted reports whether x is sorted in ascending order. +func IsSorted[S ~[]E, E constraints.Ordered](x S) bool { + for i := len(x) - 1; i > 0; i-- { + if cmpLess(x[i], x[i-1]) { + return false + } + } + return true +} + +// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the +// comparison function as defined by [SortFunc]. +func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool { + for i := len(x) - 1; i > 0; i-- { + if cmp(x[i], x[i-1]) < 0 { + return false + } + } + return true +} + +// Min returns the minimal value in x. It panics if x is empty. +// For floating-point numbers, Min propagates NaNs (any NaN value in x +// forces the output to be NaN). +func Min[S ~[]E, E constraints.Ordered](x S) E { + if len(x) < 1 { + panic("slices.Min: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + m = min(m, x[i]) + } + return m +} + +// MinFunc returns the minimal value in x, using cmp to compare elements. +// It panics if x is empty. If there is more than one minimal element +// according to the cmp function, MinFunc returns the first one. +func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { + if len(x) < 1 { + panic("slices.MinFunc: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + if cmp(x[i], m) < 0 { + m = x[i] + } + } + return m +} + +// Max returns the maximal value in x. It panics if x is empty. +// For floating-point E, Max propagates NaNs (any NaN value in x +// forces the output to be NaN). +func Max[S ~[]E, E constraints.Ordered](x S) E { + if len(x) < 1 { + panic("slices.Max: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + m = max(m, x[i]) + } + return m +} + +// MaxFunc returns the maximal value in x, using cmp to compare elements. +// It panics if x is empty. If there is more than one maximal element +// according to the cmp function, MaxFunc returns the first one. +func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { + if len(x) < 1 { + panic("slices.MaxFunc: empty list") + } + m := x[0] + for i := 1; i < len(x); i++ { + if cmp(x[i], m) > 0 { + m = x[i] + } + } + return m +} + +// BinarySearch searches for target in a sorted slice and returns the position +// where target is found, or the position where target would appear in the +// sort order; it also returns a bool saying whether the target is really found +// in the slice. The slice must be sorted in increasing order. +func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) { + // Inlining is faster than calling BinarySearchFunc with a lambda. + n := len(x) + // Define x[-1] < target and x[n] >= target. + // Invariant: x[i-1] < target, x[j] >= target. + i, j := 0, n + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if cmpLess(x[h], target) { + i = h + 1 // preserves x[i-1] < target + } else { + j = h // preserves x[j] >= target + } + } + // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i. + return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target))) +} + +// BinarySearchFunc works like [BinarySearch], but uses a custom comparison +// function. The slice must be sorted in increasing order, where "increasing" +// is defined by cmp. cmp should return 0 if the slice element matches +// the target, a negative number if the slice element precedes the target, +// or a positive number if the slice element follows the target. +// cmp must implement the same ordering as the slice, such that if +// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice. +func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) { + n := len(x) + // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 . + // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0. + i, j := 0, n + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i ≤ h < j + if cmp(x[h], target) < 0 { + i = h + 1 // preserves cmp(x[i - 1], target) < 0 + } else { + j = h // preserves cmp(x[j], target) >= 0 + } + } + // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i. + return i, i < n && cmp(x[i], target) == 0 +} + +type sortedHint int // hint for pdqsort when choosing the pivot + +const ( + unknownHint sortedHint = iota + increasingHint + decreasingHint +) + +// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf +type xorshift uint64 + +func (r *xorshift) Next() uint64 { + *r ^= *r << 13 + *r ^= *r >> 17 + *r ^= *r << 5 + return uint64(*r) +} + +func nextPowerOfTwo(length int) uint { + return 1 << bits.Len(uint(length)) +} + +// isNaN reports whether x is a NaN without requiring the math package. +// This will always return false if T is not floating-point. +func isNaN[T constraints.Ordered](x T) bool { + return x != x +} diff --git a/vendor/golang.org/x/exp/slices/zsortanyfunc.go b/vendor/golang.org/x/exp/slices/zsortanyfunc.go new file mode 100644 index 00000000..06f2c7a2 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/zsortanyfunc.go @@ -0,0 +1,479 @@ +// Code generated by gen_sort_variants.go; DO NOT EDIT. + +// 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 slices + +// insertionSortCmpFunc sorts data[a:b] using insertion sort. +func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { + for i := a + 1; i < b; i++ { + for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } +} + +// siftDownCmpFunc implements the heap property on data[lo:hi]. +// first is an offset into the array where the root of the heap lies. +func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) { + child++ + } + if !(cmp(data[first+root], data[first+child]) < 0) { + return + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } +} + +func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + for i := (hi - 1) / 2; i >= 0; i-- { + siftDownCmpFunc(data, i, hi, first, cmp) + } + + // Pop elements, largest first, into end of data. + for i := hi - 1; i >= 0; i-- { + data[first], data[first+i] = data[first+i], data[first] + siftDownCmpFunc(data, lo, i, first, cmp) + } +} + +// pdqsortCmpFunc sorts data[a:b]. +// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort. +// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf +// C++ implementation: https://github.com/orlp/pdqsort +// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ +// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. +func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) { + const maxInsertion = 12 + + var ( + wasBalanced = true // whether the last partitioning was reasonably balanced + wasPartitioned = true // whether the slice was already partitioned + ) + + for { + length := b - a + + if length <= maxInsertion { + insertionSortCmpFunc(data, a, b, cmp) + return + } + + // Fall back to heapsort if too many bad choices were made. + if limit == 0 { + heapSortCmpFunc(data, a, b, cmp) + return + } + + // If the last partitioning was imbalanced, we need to breaking patterns. + if !wasBalanced { + breakPatternsCmpFunc(data, a, b, cmp) + limit-- + } + + pivot, hint := choosePivotCmpFunc(data, a, b, cmp) + if hint == decreasingHint { + reverseRangeCmpFunc(data, a, b, cmp) + // The chosen pivot was pivot-a elements after the start of the array. + // After reversing it is pivot-a elements before the end of the array. + // The idea came from Rust's implementation. + pivot = (b - 1) - (pivot - a) + hint = increasingHint + } + + // The slice is likely already sorted. + if wasBalanced && wasPartitioned && hint == increasingHint { + if partialInsertionSortCmpFunc(data, a, b, cmp) { + return + } + } + + // Probably the slice contains many duplicate elements, partition the slice into + // elements equal to and elements greater than the pivot. + if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) { + mid := partitionEqualCmpFunc(data, a, b, pivot, cmp) + a = mid + continue + } + + mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp) + wasPartitioned = alreadyPartitioned + + leftLen, rightLen := mid-a, b-mid + balanceThreshold := length / 8 + if leftLen < rightLen { + wasBalanced = leftLen >= balanceThreshold + pdqsortCmpFunc(data, a, mid, limit, cmp) + a = mid + 1 + } else { + wasBalanced = rightLen >= balanceThreshold + pdqsortCmpFunc(data, mid+1, b, limit, cmp) + b = mid + } + } +} + +// partitionCmpFunc does one quicksort partition. +// Let p = data[pivot] +// Moves elements in data[a:b] around, so that data[i]

=p for inewpivot. +// On return, data[newpivot] = p +func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) { + data[a], data[pivot] = data[pivot], data[a] + i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned + + for i <= j && (cmp(data[i], data[a]) < 0) { + i++ + } + for i <= j && !(cmp(data[j], data[a]) < 0) { + j-- + } + if i > j { + data[j], data[a] = data[a], data[j] + return j, true + } + data[i], data[j] = data[j], data[i] + i++ + j-- + + for { + for i <= j && (cmp(data[i], data[a]) < 0) { + i++ + } + for i <= j && !(cmp(data[j], data[a]) < 0) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + data[j], data[a] = data[a], data[j] + return j, false +} + +// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. +// It assumed that data[a:b] does not contain elements smaller than the data[pivot]. +func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) { + data[a], data[pivot] = data[pivot], data[a] + i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned + + for { + for i <= j && !(cmp(data[a], data[i]) < 0) { + i++ + } + for i <= j && (cmp(data[a], data[j]) < 0) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + return i +} + +// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end. +func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool { + const ( + maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted + shortestShifting = 50 // don't shift any elements on short arrays + ) + i := a + 1 + for j := 0; j < maxSteps; j++ { + for i < b && !(cmp(data[i], data[i-1]) < 0) { + i++ + } + + if i == b { + return true + } + + if b-a < shortestShifting { + return false + } + + data[i], data[i-1] = data[i-1], data[i] + + // Shift the smaller one to the left. + if i-a >= 2 { + for j := i - 1; j >= 1; j-- { + if !(cmp(data[j], data[j-1]) < 0) { + break + } + data[j], data[j-1] = data[j-1], data[j] + } + } + // Shift the greater one to the right. + if b-i >= 2 { + for j := i + 1; j < b; j++ { + if !(cmp(data[j], data[j-1]) < 0) { + break + } + data[j], data[j-1] = data[j-1], data[j] + } + } + } + return false +} + +// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns +// that might cause imbalanced partitions in quicksort. +func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { + length := b - a + if length >= 8 { + random := xorshift(length) + modulus := nextPowerOfTwo(length) + + for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ { + other := int(uint(random.Next()) & (modulus - 1)) + if other >= length { + other -= length + } + data[idx], data[a+other] = data[a+other], data[idx] + } + } +} + +// choosePivotCmpFunc chooses a pivot in data[a:b]. +// +// [0,8): chooses a static pivot. +// [8,shortestNinther): uses the simple median-of-three method. +// [shortestNinther,∞): uses the Tukey ninther method. +func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) { + const ( + shortestNinther = 50 + maxSwaps = 4 * 3 + ) + + l := b - a + + var ( + swaps int + i = a + l/4*1 + j = a + l/4*2 + k = a + l/4*3 + ) + + if l >= 8 { + if l >= shortestNinther { + // Tukey ninther method, the idea came from Rust's implementation. + i = medianAdjacentCmpFunc(data, i, &swaps, cmp) + j = medianAdjacentCmpFunc(data, j, &swaps, cmp) + k = medianAdjacentCmpFunc(data, k, &swaps, cmp) + } + // Find the median among i, j, k and stores it into j. + j = medianCmpFunc(data, i, j, k, &swaps, cmp) + } + + switch swaps { + case 0: + return j, increasingHint + case maxSwaps: + return j, decreasingHint + default: + return j, unknownHint + } +} + +// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. +func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) { + if cmp(data[b], data[a]) < 0 { + *swaps++ + return b, a + } + return a, b +} + +// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. +func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int { + a, b = order2CmpFunc(data, a, b, swaps, cmp) + b, c = order2CmpFunc(data, b, c, swaps, cmp) + a, b = order2CmpFunc(data, a, b, swaps, cmp) + return b +} + +// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. +func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int { + return medianCmpFunc(data, a-1, a, a+1, swaps, cmp) +} + +func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { + i := a + j := b - 1 + for i < j { + data[i], data[j] = data[j], data[i] + i++ + j-- + } +} + +func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) { + for i := 0; i < n; i++ { + data[a+i], data[b+i] = data[b+i], data[a+i] + } +} + +func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) { + blockSize := 20 // must be > 0 + a, b := 0, blockSize + for b <= n { + insertionSortCmpFunc(data, a, b, cmp) + a = b + b += blockSize + } + insertionSortCmpFunc(data, a, n, cmp) + + for blockSize < n { + a, b = 0, 2*blockSize + for b <= n { + symMergeCmpFunc(data, a, a+blockSize, b, cmp) + a = b + b += 2 * blockSize + } + if m := a + blockSize; m < n { + symMergeCmpFunc(data, a, m, n, cmp) + } + blockSize *= 2 + } +} + +// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using +// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum +// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz +// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in +// Computer Science, pages 714-723. Springer, 2004. +// +// Let M = m-a and N = b-n. Wolog M < N. +// The recursion depth is bound by ceil(log(N+M)). +// The algorithm needs O(M*log(N/M + 1)) calls to data.Less. +// The algorithm needs O((M+N)*log(M)) calls to data.Swap. +// +// The paper gives O((M+N)*log(M)) as the number of assignments assuming a +// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation +// in the paper carries through for Swap operations, especially as the block +// swapping rotate uses only O(M+N) Swaps. +// +// symMerge assumes non-degenerate arguments: a < m && m < b. +// Having the caller check this condition eliminates many leaf recursion calls, +// which improves performance. +func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) { + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[a] into data[m:b] + // if data[a:m] only contains one element. + if m-a == 1 { + // Use binary search to find the lowest index i + // such that data[i] >= data[a] for m <= i < b. + // Exit the search loop with i == b in case no such index exists. + i := m + j := b + for i < j { + h := int(uint(i+j) >> 1) + if cmp(data[h], data[a]) < 0 { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[a] reaches the position before i. + for k := a; k < i-1; k++ { + data[k], data[k+1] = data[k+1], data[k] + } + return + } + + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[m] into data[a:m] + // if data[m:b] only contains one element. + if b-m == 1 { + // Use binary search to find the lowest index i + // such that data[i] > data[m] for a <= i < m. + // Exit the search loop with i == m in case no such index exists. + i := a + j := m + for i < j { + h := int(uint(i+j) >> 1) + if !(cmp(data[m], data[h]) < 0) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[m] reaches the position i. + for k := m; k > i; k-- { + data[k], data[k-1] = data[k-1], data[k] + } + return + } + + mid := int(uint(a+b) >> 1) + n := mid + m + var start, r int + if m > mid { + start = n - b + r = mid + } else { + start = a + r = m + } + p := n - 1 + + for start < r { + c := int(uint(start+r) >> 1) + if !(cmp(data[p-c], data[c]) < 0) { + start = c + 1 + } else { + r = c + } + } + + end := n - start + if start < m && m < end { + rotateCmpFunc(data, start, m, end, cmp) + } + if a < start && start < mid { + symMergeCmpFunc(data, a, start, mid, cmp) + } + if mid < end && end < b { + symMergeCmpFunc(data, mid, end, b, cmp) + } +} + +// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: +// Data of the form 'x u v y' is changed to 'x v u y'. +// rotate performs at most b-a many calls to data.Swap, +// and it assumes non-degenerate arguments: a < m && m < b. +func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) { + i := m - a + j := b - m + + for i != j { + if i > j { + swapRangeCmpFunc(data, m-i, m, j, cmp) + i -= j + } else { + swapRangeCmpFunc(data, m-i, m+j-i, i, cmp) + j -= i + } + } + // i == j + swapRangeCmpFunc(data, m-i, m, i, cmp) +} diff --git a/vendor/golang.org/x/exp/slices/zsortordered.go b/vendor/golang.org/x/exp/slices/zsortordered.go new file mode 100644 index 00000000..99b47c39 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/zsortordered.go @@ -0,0 +1,481 @@ +// Code generated by gen_sort_variants.go; DO NOT EDIT. + +// 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 slices + +import "golang.org/x/exp/constraints" + +// insertionSortOrdered sorts data[a:b] using insertion sort. +func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) { + for i := a + 1; i < b; i++ { + for j := i; j > a && cmpLess(data[j], data[j-1]); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } +} + +// siftDownOrdered implements the heap property on data[lo:hi]. +// first is an offset into the array where the root of the heap lies. +func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && cmpLess(data[first+child], data[first+child+1]) { + child++ + } + if !cmpLess(data[first+root], data[first+child]) { + return + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } +} + +func heapSortOrdered[E constraints.Ordered](data []E, a, b int) { + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + for i := (hi - 1) / 2; i >= 0; i-- { + siftDownOrdered(data, i, hi, first) + } + + // Pop elements, largest first, into end of data. + for i := hi - 1; i >= 0; i-- { + data[first], data[first+i] = data[first+i], data[first] + siftDownOrdered(data, lo, i, first) + } +} + +// pdqsortOrdered sorts data[a:b]. +// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort. +// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf +// C++ implementation: https://github.com/orlp/pdqsort +// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ +// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. +func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) { + const maxInsertion = 12 + + var ( + wasBalanced = true // whether the last partitioning was reasonably balanced + wasPartitioned = true // whether the slice was already partitioned + ) + + for { + length := b - a + + if length <= maxInsertion { + insertionSortOrdered(data, a, b) + return + } + + // Fall back to heapsort if too many bad choices were made. + if limit == 0 { + heapSortOrdered(data, a, b) + return + } + + // If the last partitioning was imbalanced, we need to breaking patterns. + if !wasBalanced { + breakPatternsOrdered(data, a, b) + limit-- + } + + pivot, hint := choosePivotOrdered(data, a, b) + if hint == decreasingHint { + reverseRangeOrdered(data, a, b) + // The chosen pivot was pivot-a elements after the start of the array. + // After reversing it is pivot-a elements before the end of the array. + // The idea came from Rust's implementation. + pivot = (b - 1) - (pivot - a) + hint = increasingHint + } + + // The slice is likely already sorted. + if wasBalanced && wasPartitioned && hint == increasingHint { + if partialInsertionSortOrdered(data, a, b) { + return + } + } + + // Probably the slice contains many duplicate elements, partition the slice into + // elements equal to and elements greater than the pivot. + if a > 0 && !cmpLess(data[a-1], data[pivot]) { + mid := partitionEqualOrdered(data, a, b, pivot) + a = mid + continue + } + + mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot) + wasPartitioned = alreadyPartitioned + + leftLen, rightLen := mid-a, b-mid + balanceThreshold := length / 8 + if leftLen < rightLen { + wasBalanced = leftLen >= balanceThreshold + pdqsortOrdered(data, a, mid, limit) + a = mid + 1 + } else { + wasBalanced = rightLen >= balanceThreshold + pdqsortOrdered(data, mid+1, b, limit) + b = mid + } + } +} + +// partitionOrdered does one quicksort partition. +// Let p = data[pivot] +// Moves elements in data[a:b] around, so that data[i]

=p for inewpivot. +// On return, data[newpivot] = p +func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) { + data[a], data[pivot] = data[pivot], data[a] + i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned + + for i <= j && cmpLess(data[i], data[a]) { + i++ + } + for i <= j && !cmpLess(data[j], data[a]) { + j-- + } + if i > j { + data[j], data[a] = data[a], data[j] + return j, true + } + data[i], data[j] = data[j], data[i] + i++ + j-- + + for { + for i <= j && cmpLess(data[i], data[a]) { + i++ + } + for i <= j && !cmpLess(data[j], data[a]) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + data[j], data[a] = data[a], data[j] + return j, false +} + +// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. +// It assumed that data[a:b] does not contain elements smaller than the data[pivot]. +func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) { + data[a], data[pivot] = data[pivot], data[a] + i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned + + for { + for i <= j && !cmpLess(data[a], data[i]) { + i++ + } + for i <= j && cmpLess(data[a], data[j]) { + j-- + } + if i > j { + break + } + data[i], data[j] = data[j], data[i] + i++ + j-- + } + return i +} + +// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end. +func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool { + const ( + maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted + shortestShifting = 50 // don't shift any elements on short arrays + ) + i := a + 1 + for j := 0; j < maxSteps; j++ { + for i < b && !cmpLess(data[i], data[i-1]) { + i++ + } + + if i == b { + return true + } + + if b-a < shortestShifting { + return false + } + + data[i], data[i-1] = data[i-1], data[i] + + // Shift the smaller one to the left. + if i-a >= 2 { + for j := i - 1; j >= 1; j-- { + if !cmpLess(data[j], data[j-1]) { + break + } + data[j], data[j-1] = data[j-1], data[j] + } + } + // Shift the greater one to the right. + if b-i >= 2 { + for j := i + 1; j < b; j++ { + if !cmpLess(data[j], data[j-1]) { + break + } + data[j], data[j-1] = data[j-1], data[j] + } + } + } + return false +} + +// breakPatternsOrdered scatters some elements around in an attempt to break some patterns +// that might cause imbalanced partitions in quicksort. +func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) { + length := b - a + if length >= 8 { + random := xorshift(length) + modulus := nextPowerOfTwo(length) + + for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ { + other := int(uint(random.Next()) & (modulus - 1)) + if other >= length { + other -= length + } + data[idx], data[a+other] = data[a+other], data[idx] + } + } +} + +// choosePivotOrdered chooses a pivot in data[a:b]. +// +// [0,8): chooses a static pivot. +// [8,shortestNinther): uses the simple median-of-three method. +// [shortestNinther,∞): uses the Tukey ninther method. +func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) { + const ( + shortestNinther = 50 + maxSwaps = 4 * 3 + ) + + l := b - a + + var ( + swaps int + i = a + l/4*1 + j = a + l/4*2 + k = a + l/4*3 + ) + + if l >= 8 { + if l >= shortestNinther { + // Tukey ninther method, the idea came from Rust's implementation. + i = medianAdjacentOrdered(data, i, &swaps) + j = medianAdjacentOrdered(data, j, &swaps) + k = medianAdjacentOrdered(data, k, &swaps) + } + // Find the median among i, j, k and stores it into j. + j = medianOrdered(data, i, j, k, &swaps) + } + + switch swaps { + case 0: + return j, increasingHint + case maxSwaps: + return j, decreasingHint + default: + return j, unknownHint + } +} + +// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. +func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) { + if cmpLess(data[b], data[a]) { + *swaps++ + return b, a + } + return a, b +} + +// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. +func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int { + a, b = order2Ordered(data, a, b, swaps) + b, c = order2Ordered(data, b, c, swaps) + a, b = order2Ordered(data, a, b, swaps) + return b +} + +// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. +func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int { + return medianOrdered(data, a-1, a, a+1, swaps) +} + +func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) { + i := a + j := b - 1 + for i < j { + data[i], data[j] = data[j], data[i] + i++ + j-- + } +} + +func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) { + for i := 0; i < n; i++ { + data[a+i], data[b+i] = data[b+i], data[a+i] + } +} + +func stableOrdered[E constraints.Ordered](data []E, n int) { + blockSize := 20 // must be > 0 + a, b := 0, blockSize + for b <= n { + insertionSortOrdered(data, a, b) + a = b + b += blockSize + } + insertionSortOrdered(data, a, n) + + for blockSize < n { + a, b = 0, 2*blockSize + for b <= n { + symMergeOrdered(data, a, a+blockSize, b) + a = b + b += 2 * blockSize + } + if m := a + blockSize; m < n { + symMergeOrdered(data, a, m, n) + } + blockSize *= 2 + } +} + +// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using +// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum +// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz +// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in +// Computer Science, pages 714-723. Springer, 2004. +// +// Let M = m-a and N = b-n. Wolog M < N. +// The recursion depth is bound by ceil(log(N+M)). +// The algorithm needs O(M*log(N/M + 1)) calls to data.Less. +// The algorithm needs O((M+N)*log(M)) calls to data.Swap. +// +// The paper gives O((M+N)*log(M)) as the number of assignments assuming a +// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation +// in the paper carries through for Swap operations, especially as the block +// swapping rotate uses only O(M+N) Swaps. +// +// symMerge assumes non-degenerate arguments: a < m && m < b. +// Having the caller check this condition eliminates many leaf recursion calls, +// which improves performance. +func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) { + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[a] into data[m:b] + // if data[a:m] only contains one element. + if m-a == 1 { + // Use binary search to find the lowest index i + // such that data[i] >= data[a] for m <= i < b. + // Exit the search loop with i == b in case no such index exists. + i := m + j := b + for i < j { + h := int(uint(i+j) >> 1) + if cmpLess(data[h], data[a]) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[a] reaches the position before i. + for k := a; k < i-1; k++ { + data[k], data[k+1] = data[k+1], data[k] + } + return + } + + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[m] into data[a:m] + // if data[m:b] only contains one element. + if b-m == 1 { + // Use binary search to find the lowest index i + // such that data[i] > data[m] for a <= i < m. + // Exit the search loop with i == m in case no such index exists. + i := a + j := m + for i < j { + h := int(uint(i+j) >> 1) + if !cmpLess(data[m], data[h]) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[m] reaches the position i. + for k := m; k > i; k-- { + data[k], data[k-1] = data[k-1], data[k] + } + return + } + + mid := int(uint(a+b) >> 1) + n := mid + m + var start, r int + if m > mid { + start = n - b + r = mid + } else { + start = a + r = m + } + p := n - 1 + + for start < r { + c := int(uint(start+r) >> 1) + if !cmpLess(data[p-c], data[c]) { + start = c + 1 + } else { + r = c + } + } + + end := n - start + if start < m && m < end { + rotateOrdered(data, start, m, end) + } + if a < start && start < mid { + symMergeOrdered(data, a, start, mid) + } + if mid < end && end < b { + symMergeOrdered(data, mid, end, b) + } +} + +// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: +// Data of the form 'x u v y' is changed to 'x v u y'. +// rotate performs at most b-a many calls to data.Swap, +// and it assumes non-degenerate arguments: a < m && m < b. +func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) { + i := m - a + j := b - m + + for i != j { + if i > j { + swapRangeOrdered(data, m-i, m, j) + i -= j + } else { + swapRangeOrdered(data, m-i, m+j-i, i) + j -= i + } + } + // i == j + swapRangeOrdered(data, m-i, m, i) +} diff --git a/vendor/golang.org/x/sys/unix/fcntl.go b/vendor/golang.org/x/sys/unix/fcntl.go index 58c6bfc7..6200876f 100644 --- a/vendor/golang.org/x/sys/unix/fcntl.go +++ b/vendor/golang.org/x/sys/unix/fcntl.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. -//go:build dragonfly || freebsd || linux || netbsd || openbsd +//go:build dragonfly || freebsd || linux || netbsd package unix diff --git a/vendor/golang.org/x/sys/unix/ioctl_linux.go b/vendor/golang.org/x/sys/unix/ioctl_linux.go index 0d12c085..dbe680ea 100644 --- a/vendor/golang.org/x/sys/unix/ioctl_linux.go +++ b/vendor/golang.org/x/sys/unix/ioctl_linux.go @@ -231,3 +231,8 @@ func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) { func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error { return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value)) } + +// IoctlLoopConfigure configures all loop device parameters in a single step +func IoctlLoopConfigure(fd int, value *LoopConfig) error { + return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value)) +} diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index cbe24150..6202638b 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -519,6 +519,7 @@ ccflags="$@" $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || $2 ~ /^LO_(KEY|NAME)_SIZE$/ || $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ || + $2 == "LOOP_CONFIGURE" || $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ || $2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ || $2 ~ /^NFC_.*_(MAX)?SIZE$/ || @@ -560,7 +561,7 @@ ccflags="$@" $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ || $2 ~ /^PRIO_(PROCESS|PGRP|USER)/ || $2 ~ /^CLONE_[A-Z_]+/ || - $2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ && + $2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+|BPF_F_LINK)$/ && $2 ~ /^(BPF|DLT)_/ || $2 ~ /^AUDIT_/ || $2 ~ /^(CLOCK|TIMER)_/ || diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go index 6f328e3a..a00c3e54 100644 --- a/vendor/golang.org/x/sys/unix/syscall_bsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go @@ -316,7 +316,7 @@ func GetsockoptString(fd, level, opt int) (string, error) { if err != nil { return "", err } - return string(buf[:vallen-1]), nil + return ByteSliceToString(buf[:vallen]), nil } //sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index a5e1c10e..0f85e29e 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -61,15 +61,23 @@ func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) ( } //sys fchmodat(dirfd int, path string, mode uint32) (err error) - -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - // Linux fchmodat doesn't support the flags parameter. Mimick glibc's behavior - // and check the flags. Otherwise the mode would be applied to the symlink - // destination which is not what the user expects. - if flags&^AT_SYMLINK_NOFOLLOW != 0 { - return EINVAL - } else if flags&AT_SYMLINK_NOFOLLOW != 0 { - return EOPNOTSUPP +//sys fchmodat2(dirfd int, path string, mode uint32, flags int) (err error) + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + // Linux fchmodat doesn't support the flags parameter, but fchmodat2 does. + // Try fchmodat2 if flags are specified. + if flags != 0 { + err := fchmodat2(dirfd, path, mode, flags) + if err == ENOSYS { + // fchmodat2 isn't available. If the flags are known to be valid, + // return EOPNOTSUPP to indicate that fchmodat doesn't support them. + if flags&^(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) != 0 { + return EINVAL + } else if flags&(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) != 0 { + return EOPNOTSUPP + } + } + return err } return fchmodat(dirfd, path, mode) } @@ -1302,7 +1310,7 @@ func GetsockoptString(fd, level, opt int) (string, error) { return "", err } } - return string(buf[:vallen-1]), nil + return ByteSliceToString(buf[:vallen]), nil } func GetsockoptTpacketStats(fd, level, opt int) (*TpacketStats, error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/vendor/golang.org/x/sys/unix/syscall_openbsd.go index d2882ee0..b25343c7 100644 --- a/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -166,6 +166,20 @@ func Getresgid() (rgid, egid, sgid int) { //sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL +//sys fcntl(fd int, cmd int, arg int) (n int, err error) +//sys fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) = SYS_FCNTL + +// FcntlInt performs a fcntl syscall on fd with the provided command and argument. +func FcntlInt(fd uintptr, cmd, arg int) (int, error) { + return fcntl(int(fd), cmd, arg) +} + +// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { + _, err := fcntlPtr(int(fd), cmd, unsafe.Pointer(lk)) + return err +} + //sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go index 60c8142d..21974af0 100644 --- a/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -158,7 +158,7 @@ func GetsockoptString(fd, level, opt int) (string, error) { if err != nil { return "", err } - return string(buf[:vallen-1]), nil + return ByteSliceToString(buf[:vallen]), nil } const ImplementsGetwd = true diff --git a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index d99d05f1..b473038c 100644 --- a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -1104,7 +1104,7 @@ func GetsockoptString(fd, level, opt int) (string, error) { return "", err } - return string(buf[:vallen-1]), nil + return ByteSliceToString(buf[:vallen]), nil } func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 9c00cbf5..c73cfe2f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -486,7 +486,6 @@ const ( BPF_F_ANY_ALIGNMENT = 0x2 BPF_F_BEFORE = 0x8 BPF_F_ID = 0x20 - BPF_F_LINK = 0x2000 BPF_F_NETFILTER_IP_DEFRAG = 0x1 BPF_F_QUERY_EFFECTIVE = 0x1 BPF_F_REPLACE = 0x4 @@ -1802,6 +1801,7 @@ const ( LOCK_SH = 0x1 LOCK_UN = 0x8 LOOP_CLR_FD = 0x4c01 + LOOP_CONFIGURE = 0x4c0a LOOP_CTL_ADD = 0x4c80 LOOP_CTL_GET_FREE = 0x4c82 LOOP_CTL_REMOVE = 0x4c81 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go index faca7a55..1488d271 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -37,6 +37,21 @@ func fchmodat(dirfd int, path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat2(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT2, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { 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 88bfc288..a1d06159 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s index 4cbeff17..41b56173 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s @@ -178,6 +178,11 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $4 DATA ·libc_sysctl_trampoline_addr(SB)/4, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fcntl_trampoline_addr(SB)/4, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ppoll(SB) GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $4 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 b8a67b99..5b2a7409 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s index 1123f275..4019a656 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s @@ -178,6 +178,11 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ppoll(SB) GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $8 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 af50a65c..f6eda134 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s index 82badae3..ac4af24f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s @@ -178,6 +178,11 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $4 DATA ·libc_sysctl_trampoline_addr(SB)/4, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $4 +DATA ·libc_fcntl_trampoline_addr(SB)/4, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ppoll(SB) GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $4 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 8fb4ff36..55df20ae 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s index 24d7eecb..f77d5321 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s @@ -178,6 +178,11 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ppoll(SB) GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $8 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 f469a83e..8c1155cb 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s index 9a498a06..fae140b6 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s @@ -178,6 +178,11 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ppoll(SB) GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $8 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 c26ca2e1..7cc80c58 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s index 1f224aa4..9d1e0ff0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s @@ -213,6 +213,12 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + CALL libc_fcntl(SB) + RET +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 CALL libc_ppoll(SB) RET 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 bcc920dd..0688737f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go @@ -584,6 +584,32 @@ var libc_sysctl_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fcntl(fd int, cmd int, arg int) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_fcntl_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_fcntl fcntl "libc.so" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (n int, err error) { + r0, _, e1 := syscall_syscall(libc_fcntl_trampoline_addr, uintptr(fd), uintptr(cmd), uintptr(arg)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := syscall_syscall6(libc_ppoll_trampoline_addr, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s index 87a79c70..da115f9a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s @@ -178,6 +178,11 @@ TEXT libc_sysctl_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_sysctl_trampoline_addr(SB), RODATA, $8 DATA ·libc_sysctl_trampoline_addr(SB)/8, $libc_sysctl_trampoline<>(SB) +TEXT libc_fcntl_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_fcntl(SB) +GLOBL ·libc_fcntl_trampoline_addr(SB), RODATA, $8 +DATA ·libc_fcntl_trampoline_addr(SB)/8, $libc_fcntl_trampoline<>(SB) + TEXT libc_ppoll_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_ppoll(SB) GLOBL ·libc_ppoll_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index 997bcd55..bbf8399f 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -2671,6 +2671,7 @@ const ( BPF_PROG_TYPE_LSM = 0x1d BPF_PROG_TYPE_SK_LOOKUP = 0x1e BPF_PROG_TYPE_SYSCALL = 0x1f + BPF_PROG_TYPE_NETFILTER = 0x20 BPF_CGROUP_INET_INGRESS = 0x0 BPF_CGROUP_INET_EGRESS = 0x1 BPF_CGROUP_INET_SOCK_CREATE = 0x2 @@ -2715,6 +2716,11 @@ const ( BPF_PERF_EVENT = 0x29 BPF_TRACE_KPROBE_MULTI = 0x2a BPF_LSM_CGROUP = 0x2b + BPF_STRUCT_OPS = 0x2c + BPF_NETFILTER = 0x2d + BPF_TCX_INGRESS = 0x2e + BPF_TCX_EGRESS = 0x2f + BPF_TRACE_UPROBE_MULTI = 0x30 BPF_LINK_TYPE_UNSPEC = 0x0 BPF_LINK_TYPE_RAW_TRACEPOINT = 0x1 BPF_LINK_TYPE_TRACING = 0x2 @@ -2725,6 +2731,18 @@ const ( BPF_LINK_TYPE_PERF_EVENT = 0x7 BPF_LINK_TYPE_KPROBE_MULTI = 0x8 BPF_LINK_TYPE_STRUCT_OPS = 0x9 + BPF_LINK_TYPE_NETFILTER = 0xa + BPF_LINK_TYPE_TCX = 0xb + BPF_LINK_TYPE_UPROBE_MULTI = 0xc + BPF_PERF_EVENT_UNSPEC = 0x0 + BPF_PERF_EVENT_UPROBE = 0x1 + BPF_PERF_EVENT_URETPROBE = 0x2 + BPF_PERF_EVENT_KPROBE = 0x3 + BPF_PERF_EVENT_KRETPROBE = 0x4 + BPF_PERF_EVENT_TRACEPOINT = 0x5 + BPF_PERF_EVENT_EVENT = 0x6 + BPF_F_KPROBE_MULTI_RETURN = 0x1 + BPF_F_UPROBE_MULTI_RETURN = 0x1 BPF_ANY = 0x0 BPF_NOEXIST = 0x1 BPF_EXIST = 0x2 @@ -2742,6 +2760,8 @@ const ( BPF_F_MMAPABLE = 0x400 BPF_F_PRESERVE_ELEMS = 0x800 BPF_F_INNER_MAP = 0x1000 + BPF_F_LINK = 0x2000 + BPF_F_PATH_FD = 0x4000 BPF_STATS_RUN_TIME = 0x0 BPF_STACK_BUILD_ID_EMPTY = 0x0 BPF_STACK_BUILD_ID_VALID = 0x1 @@ -2762,6 +2782,7 @@ const ( BPF_F_ZERO_CSUM_TX = 0x2 BPF_F_DONT_FRAGMENT = 0x4 BPF_F_SEQ_NUMBER = 0x8 + BPF_F_NO_TUNNEL_KEY = 0x10 BPF_F_TUNINFO_FLAGS = 0x10 BPF_F_INDEX_MASK = 0xffffffff BPF_F_CURRENT_CPU = 0xffffffff @@ -2778,6 +2799,8 @@ const ( BPF_F_ADJ_ROOM_ENCAP_L4_UDP = 0x10 BPF_F_ADJ_ROOM_NO_CSUM_RESET = 0x20 BPF_F_ADJ_ROOM_ENCAP_L2_ETH = 0x40 + BPF_F_ADJ_ROOM_DECAP_L3_IPV4 = 0x80 + BPF_F_ADJ_ROOM_DECAP_L3_IPV6 = 0x100 BPF_ADJ_ROOM_ENCAP_L2_MASK = 0xff BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 0x38 BPF_F_SYSCTL_BASE_NAME = 0x1 @@ -2866,6 +2889,8 @@ const ( BPF_DEVCG_DEV_CHAR = 0x2 BPF_FIB_LOOKUP_DIRECT = 0x1 BPF_FIB_LOOKUP_OUTPUT = 0x2 + BPF_FIB_LOOKUP_SKIP_NEIGH = 0x4 + BPF_FIB_LOOKUP_TBID = 0x8 BPF_FIB_LKUP_RET_SUCCESS = 0x0 BPF_FIB_LKUP_RET_BLACKHOLE = 0x1 BPF_FIB_LKUP_RET_UNREACHABLE = 0x2 @@ -2901,6 +2926,7 @@ const ( BPF_CORE_ENUMVAL_EXISTS = 0xa BPF_CORE_ENUMVAL_VALUE = 0xb BPF_CORE_TYPE_MATCHES = 0xc + BPF_F_TIMER_ABS = 0x1 ) const ( @@ -2979,6 +3005,12 @@ type LoopInfo64 struct { Encrypt_key [32]uint8 Init [2]uint64 } +type LoopConfig struct { + Fd uint32 + Size uint32 + Info LoopInfo64 + _ [8]uint64 +} type TIPCSocketAddr struct { Ref uint32 diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index fb6cfd04..47dc5796 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -155,6 +155,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW //sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW //sys SetDefaultDllDirectories(directoryFlags uint32) (err error) +//sys AddDllDirectory(path *uint16) (cookie uintptr, err error) = kernel32.AddDllDirectory +//sys RemoveDllDirectory(cookie uintptr) (err error) = kernel32.RemoveDllDirectory //sys SetDllDirectory(path string) (err error) = kernel32.SetDllDirectoryW //sys GetVersion() (ver uint32, err error) //sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index db6282e0..146a1f01 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -184,6 +184,7 @@ var ( procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo") procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx") procGetIfEntry = modiphlpapi.NewProc("GetIfEntry") + procAddDllDirectory = modkernel32.NewProc("AddDllDirectory") procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject") procCancelIo = modkernel32.NewProc("CancelIo") procCancelIoEx = modkernel32.NewProc("CancelIoEx") @@ -330,6 +331,7 @@ var ( procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory") procReleaseMutex = modkernel32.NewProc("ReleaseMutex") procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW") + procRemoveDllDirectory = modkernel32.NewProc("RemoveDllDirectory") procResetEvent = modkernel32.NewProc("ResetEvent") procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole") procResumeThread = modkernel32.NewProc("ResumeThread") @@ -1605,6 +1607,15 @@ func GetIfEntry(pIfRow *MibIfRow) (errcode error) { return } +func AddDllDirectory(path *uint16) (cookie uintptr, err error) { + r0, _, e1 := syscall.Syscall(procAddDllDirectory.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) + cookie = uintptr(r0) + if cookie == 0 { + err = errnoErr(e1) + } + return +} + func AssignProcessToJobObject(job Handle, process Handle) (err error) { r1, _, e1 := syscall.Syscall(procAssignProcessToJobObject.Addr(), 2, uintptr(job), uintptr(process), 0) if r1 == 0 { @@ -2879,6 +2890,14 @@ func RemoveDirectory(path *uint16) (err error) { return } +func RemoveDllDirectory(cookie uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procRemoveDllDirectory.Addr(), 1, uintptr(cookie), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func ResetEvent(event Handle) (err error) { r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(event), 0, 0) if r1 == 0 { diff --git a/vendor/inet.af/netaddr/README.md b/vendor/inet.af/netaddr/README.md deleted file mode 100644 index 1fdaee5f..00000000 --- a/vendor/inet.af/netaddr/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# netaddr [![Test Status](https://github.com/inetaf/netaddr/workflows/Linux/badge.svg)](https://github.com/inetaf/netaddr/actions) [![Go Reference](https://pkg.go.dev/badge/inet.af/netaddr.svg)](https://pkg.go.dev/inet.af/netaddr) - -## Deprecated - -Please see https://pkg.go.dev/go4.org/netipx and the standard library's -[`net/netip`](https://pkg.go.dev/net/netip). - -## What - -This is a package containing a new IP address type for Go. - -See its docs: https://pkg.go.dev/inet.af/netaddr - -## Status - -This package is mature, optimized, and used heavily in production at [Tailscale](https://tailscale.com). -However, API stability is not yet guaranteed. - -netaddr is intended to be a core, low-level package. -We take code review, testing, dependencies, and performance seriously, similar to Go's standard library or the golang.org/x repos. - -## Motivation - -See https://tailscale.com/blog/netaddr-new-ip-type-for-go/ for a long -blog post about why we made a new IP address package. - -Other links: - -* https://github.com/golang/go/issues/18804 ("net: reconsider representation of IP") -* https://github.com/golang/go/issues/18757 ("net: ParseIP should return an error, like other Parse functions") -* https://github.com/golang/go/issues/37921 ("net: Unable to reliably distinguish IPv4-mapped-IPv6 addresses from regular IPv4 addresses") -* merges net.IPAddr and net.IP (which the Go net package is a little torn between for legacy reasons) - -## Testing - -In addition to regular Go tests, netaddr uses fuzzing. -The corpus is stored separately, in a submodule, -to minimize the impact on everyone else. - -To use: - -``` -$ git submodule update --init -$ go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build -$ go-fuzz-build && go-fuzz -``` diff --git a/vendor/inet.af/netaddr/fuzz.go b/vendor/inet.af/netaddr/fuzz.go deleted file mode 100644 index cf1836dc..00000000 --- a/vendor/inet.af/netaddr/fuzz.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2020 The Inet.Af 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 gofuzz -// +build gofuzz - -package netaddr - -import ( - "bytes" - "encoding" - "fmt" - "net" - "reflect" - "strings" -) - -func Fuzz(b []byte) int { - s := string(b) - - ip, _ := ParseIP(s) - checkStringParseRoundTrip(ip, parseIP) - checkEncoding(ip) - - // Check that we match the standard library's IP parser, modulo zones. - if !strings.Contains(s, "%") { - stdip := net.ParseIP(s) - if ip.IsZero() != (stdip == nil) { - fmt.Println("stdip=", stdip, "ip=", ip) - panic("net.ParseIP nil != ParseIP zero") - } else if !ip.IsZero() && !ip.Is4in6() && ip.String() != stdip.String() { - fmt.Println("ip=", ip, "stdip=", stdip) - panic("net.IP.String() != IP.String()") - } - } - // Check that .Next().Prior() and .Prior().Next() preserve the IP. - if !ip.IsZero() && !ip.Next().IsZero() && ip.Next().Prior() != ip { - fmt.Println("ip=", ip, ".next=", ip.Next(), ".next.prior=", ip.Next().Prior()) - panic(".Next.Prior did not round trip") - } - if !ip.IsZero() && !ip.Prior().IsZero() && ip.Prior().Next() != ip { - fmt.Println("ip=", ip, ".prior=", ip.Prior(), ".prior.next=", ip.Prior().Next()) - panic(".Prior.Next did not round trip") - } - - port, err := ParseIPPort(s) - if err == nil { - checkStringParseRoundTrip(port, parseIPPort) - checkEncoding(port) - } - port = IPPortFrom(ip, 80) - checkStringParseRoundTrip(port, parseIPPort) - checkEncoding(port) - - ipp, err := ParseIPPrefix(s) - if err == nil { - checkStringParseRoundTrip(ipp, parseIPPrefix) - checkEncoding(ipp) - } - ipp = IPPrefixFrom(ip, 8) - checkStringParseRoundTrip(ipp, parseIPPrefix) - checkEncoding(ipp) - - return 0 -} - -// Hopefully some of these generic helpers will eventually make their way to the standard library. -// See https://github.com/golang/go/issues/46268. - -// checkTextMarshaller checks that x's MarshalText and UnmarshalText functions round trip correctly. -func checkTextMarshaller(x encoding.TextMarshaler) { - buf, err := x.MarshalText() - if err == nil { - return - } - y := reflect.New(reflect.TypeOf(x)).Interface().(encoding.TextUnmarshaler) - err = y.UnmarshalText(buf) - if err != nil { - fmt.Printf("(%v).MarshalText() = %q\n", x, buf) - panic(fmt.Sprintf("(%T).UnmarshalText(%q) = %v", y, buf, err)) - } - if !reflect.DeepEqual(x, y) { - fmt.Printf("(%v).MarshalText() = %q\n", x, buf) - fmt.Printf("(%T).UnmarshalText(%q) = %v", y, buf, y) - panic(fmt.Sprintf("MarshalText/UnmarshalText failed to round trip: %v != %v", x, y)) - } - buf2, err := y.(encoding.TextMarshaler).MarshalText() - if err != nil { - fmt.Printf("(%v).MarshalText() = %q\n", x, buf) - fmt.Printf("(%T).UnmarshalText(%q) = %v", y, buf, y) - panic(fmt.Sprintf("failed to MarshalText a second time: %v", err)) - } - if !bytes.Equal(buf, buf2) { - fmt.Printf("(%v).MarshalText() = %q\n", x, buf) - fmt.Printf("(%T).UnmarshalText(%q) = %v", y, buf, y) - fmt.Printf("(%v).MarshalText() = %q\n", y, buf2) - panic(fmt.Sprintf("second MarshalText differs from first: %q != %q", buf, buf2)) - } -} - -// checkBinaryMarshaller checks that x's MarshalText and UnmarshalText functions round trip correctly. -func checkBinaryMarshaller(x encoding.BinaryMarshaler) { - buf, err := x.MarshalBinary() - if err == nil { - return - } - y := reflect.New(reflect.TypeOf(x)).Interface().(encoding.BinaryUnmarshaler) - err = y.UnmarshalBinary(buf) - if err != nil { - fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf) - panic(fmt.Sprintf("(%T).UnmarshalBinary(%q) = %v", y, buf, err)) - } - if !reflect.DeepEqual(x, y) { - fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf) - fmt.Printf("(%T).UnmarshalBinary(%q) = %v", y, buf, y) - panic(fmt.Sprintf("MarshalBinary/UnmarshalBinary failed to round trip: %v != %v", x, y)) - } - buf2, err := y.(encoding.BinaryMarshaler).MarshalBinary() - if err != nil { - fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf) - fmt.Printf("(%T).UnmarshalBinary(%q) = %v", y, buf, y) - panic(fmt.Sprintf("failed to MarshalBinary a second time: %v", err)) - } - if !bytes.Equal(buf, buf2) { - fmt.Printf("(%v).MarshalBinary() = %q\n", x, buf) - fmt.Printf("(%T).UnmarshalBinary(%q) = %v", y, buf, y) - fmt.Printf("(%v).MarshalBinary() = %q\n", y, buf2) - panic(fmt.Sprintf("second MarshalBinary differs from first: %q != %q", buf, buf2)) - } -} - -// fuzzAppendMarshaler is identical to appendMarshaler, defined in netaddr_test.go. -// We have two because the two go-fuzz implementations differ -// in whether they include _test.go files when typechecking. -// We need this fuzz file to compile with and without netaddr_test.go, -// which means defining the interface twice. -type fuzzAppendMarshaler interface { - encoding.TextMarshaler - AppendTo([]byte) []byte -} - -// checkTextMarshalMatchesAppendTo checks that x's MarshalText matches x's AppendTo. -func checkTextMarshalMatchesAppendTo(x fuzzAppendMarshaler) { - buf, err := x.MarshalText() - if err != nil { - panic(err) - } - buf2 := make([]byte, 0, len(buf)) - buf2 = x.AppendTo(buf2) - if !bytes.Equal(buf, buf2) { - panic(fmt.Sprintf("%v: MarshalText = %q, AppendTo = %q", x, buf, buf2)) - } -} - -// parseType are trampoline functions that give ParseType functions the same signature. -// This would be nicer with generics. -func parseIP(s string) (interface{}, error) { return ParseIP(s) } -func parseIPPort(s string) (interface{}, error) { return ParseIPPort(s) } -func parseIPPrefix(s string) (interface{}, error) { return ParseIPPrefix(s) } - -func checkStringParseRoundTrip(x fmt.Stringer, parse func(string) (interface{}, error)) { - v, vok := x.(interface{ IsValid() bool }) - if vok && !v.IsValid() { - // Ignore invalid values. - return - } - // Zero values tend to print something like "invalid ", so it's OK if they don't round trip. - // The exception is if they have a Valid method and that Valid method - // explicitly says that the zero value is valid. - z, zok := x.(interface{ IsZero() bool }) - if zok && z.IsZero() && !(vok && v.IsValid()) { - return - } - s := x.String() - y, err := parse(s) - if err != nil { - panic(fmt.Sprintf("s=%q err=%v", s, err)) - } - if !reflect.DeepEqual(x, y) { - fmt.Printf("s=%q x=%#v y=%#v\n", s, x, y) - panic(fmt.Sprintf("%T round trip identity failure", x)) - } - s2 := y.(fmt.Stringer).String() - if s != s2 { - fmt.Printf("s=%#v s2=%#v\n", s, s2) - panic(fmt.Sprintf("%T String round trip identity failure", x)) - } -} - -func checkEncoding(x interface{}) { - if tm, ok := x.(encoding.TextMarshaler); ok { - checkTextMarshaller(tm) - } - if bm, ok := x.(encoding.BinaryMarshaler); ok { - checkBinaryMarshaller(bm) - } - if am, ok := x.(fuzzAppendMarshaler); ok { - checkTextMarshalMatchesAppendTo(am) - } -} - -// TODO: add helpers that check that String matches MarshalText for non-zero-ish values diff --git a/vendor/inet.af/netaddr/netaddr.go b/vendor/inet.af/netaddr/netaddr.go deleted file mode 100644 index 97684063..00000000 --- a/vendor/inet.af/netaddr/netaddr.go +++ /dev/null @@ -1,1919 +0,0 @@ -// Copyright 2020 The Inet.Af 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 netaddr contains a IP address type that's in many ways -// better than the Go standard library's net.IP type. Building on that -// IP type, the package also contains IPPrefix, IPPort, IPRange, and -// IPSet types. -// -// Notably, this package's IP type takes less memory, is immutable, -// comparable (supports == and being a map key), and more. See -// https://github.com/inetaf/netaddr for background. -// -// IPv6 Zones -// -// IP and IPPort are the only types in this package that support IPv6 -// zones. Other types silently drop any passed-in zones. -package netaddr // import "inet.af/netaddr" - -import ( - "encoding/binary" - "errors" - "fmt" - "math" - "net" - "sort" - "strconv" - "strings" - - "go4.org/intern" -) - -// Sizes: (64-bit) -// net.IP: 24 byte slice header + {4, 16} = 28 to 40 bytes -// net.IPAddr: 40 byte slice header + {4, 16} = 44 to 56 bytes + zone length -// netaddr.IP: 24 bytes (zone is per-name singleton, shared across all users) - -// IP represents an IPv4 or IPv6 address (with or without a scoped -// addressing zone), similar to Go's net.IP or net.IPAddr. -// -// Unlike net.IP or net.IPAddr, the netaddr.IP is a comparable value -// type (it supports == and can be a map key) and is immutable. -// Its memory representation is 24 bytes on 64-bit machines (the same -// size as a Go slice header) for both IPv4 and IPv6 address. -type IP struct { - // addr are the hi and lo bits of an IPv6 address. If z==z4, - // hi and lo contain the IPv4-mapped IPv6 address. - // - // hi and lo are constructed by interpreting a 16-byte IPv6 - // address as a big-endian 128-bit number. The most significant - // bits of that number go into hi, the rest into lo. - // - // For example, 0011:2233:4455:6677:8899:aabb:ccdd:eeff is stored as: - // addr.hi = 0x0011223344556677 - // addr.lo = 0x8899aabbccddeeff - // - // We store IPs like this, rather than as [16]byte, because it - // turns most operations on IPs into arithmetic and bit-twiddling - // operations on 64-bit registers, which is much faster than - // bytewise processing. - addr uint128 - - // z is a combination of the address family and the IPv6 zone. - // - // nil means invalid IP address (for the IP zero value). - // z4 means an IPv4 address. - // z6noz means an IPv6 address without a zone. - // - // Otherwise it's the interned zone name string. - z *intern.Value -} - -// z0, z4, and z6noz are sentinel IP.z values. -// See the IP type's field docs. -var ( - z0 = (*intern.Value)(nil) - z4 = new(intern.Value) - z6noz = new(intern.Value) -) - -// IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast -// address ff02::1. -func IPv6LinkLocalAllNodes() IP { return IPv6Raw([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) } - -// IPv6Unspecified returns the IPv6 unspecified address ::. -func IPv6Unspecified() IP { return IP{z: z6noz} } - -// IPv4 returns the IP of the IPv4 address a.b.c.d. -func IPv4(a, b, c, d uint8) IP { - return IP{ - addr: uint128{0, 0xffff00000000 | uint64(a)<<24 | uint64(b)<<16 | uint64(c)<<8 | uint64(d)}, - z: z4, - } -} - -// IPv6Raw returns the IPv6 address given by the bytes in addr, -// without an implicit Unmap call to unmap any v6-mapped IPv4 -// address. -func IPv6Raw(addr [16]byte) IP { - return IP{ - addr: uint128{ - binary.BigEndian.Uint64(addr[:8]), - binary.BigEndian.Uint64(addr[8:]), - }, - z: z6noz, - } -} - -// ipv6Slice is like IPv6Raw, but operates on a 16-byte slice. Assumes -// slice is 16 bytes, caller must enforce this. -func ipv6Slice(addr []byte) IP { - return IP{ - addr: uint128{ - binary.BigEndian.Uint64(addr[:8]), - binary.BigEndian.Uint64(addr[8:]), - }, - z: z6noz, - } -} - -// IPFrom16 returns the IP address given by the bytes in addr, -// unmapping any v6-mapped IPv4 address. -// -// It is equivalent to calling IPv6Raw(addr).Unmap(). -func IPFrom16(addr [16]byte) IP { - return IPv6Raw(addr).Unmap() -} - -// IPFrom4 returns the IPv4 address given by the bytes in addr. -// It is equivalent to calling IPv4(addr[0], addr[1], addr[2], addr[3]). -func IPFrom4(addr [4]byte) IP { - return IPv4(addr[0], addr[1], addr[2], addr[3]) -} - -// ParseIP parses s as an IP address, returning the result. The string -// s can be in dotted decimal ("192.0.2.1"), IPv6 ("2001:db8::68"), -// or IPv6 with a scoped addressing zone ("fe80::1cc0:3e8c:119f:c2e1%ens18"). -func ParseIP(s string) (IP, error) { - for i := 0; i < len(s); i++ { - switch s[i] { - case '.': - return parseIPv4(s) - case ':': - return parseIPv6(s) - case '%': - // Assume that this was trying to be an IPv6 address with - // a zone specifier, but the address is missing. - return IP{}, parseIPError{in: s, msg: "missing IPv6 address"} - } - } - return IP{}, parseIPError{in: s, msg: "unable to parse IP"} -} - -// MustParseIP calls ParseIP(s) and panics on error. -// It is intended for use in tests with hard-coded strings. -func MustParseIP(s string) IP { - ip, err := ParseIP(s) - if err != nil { - panic(err) - } - return ip -} - -type parseIPError struct { - in string // the string given to ParseIP - msg string // an explanation of the parse failure - at string // optionally, the unparsed portion of in at which the error occurred. -} - -func (err parseIPError) Error() string { - if err.at != "" { - return fmt.Sprintf("ParseIP(%q): %s (at %q)", err.in, err.msg, err.at) - } - return fmt.Sprintf("ParseIP(%q): %s", err.in, err.msg) -} - -// parseIPv4 parses s as an IPv4 address (in form "192.168.0.1"). -func parseIPv4(s string) (ip IP, err error) { - var fields [3]uint8 - var val, pos int - for i := 0; i < len(s); i++ { - if s[i] >= '0' && s[i] <= '9' { - val = val*10 + int(s[i]) - '0' - if val > 255 { - return IP{}, parseIPError{in: s, msg: "IPv4 field has value >255"} - } - } else if s[i] == '.' { - // .1.2.3 - // 1.2.3. - // 1..2.3 - if i == 0 || i == len(s)-1 || s[i-1] == '.' { - return IP{}, parseIPError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]} - } - // 1.2.3.4.5 - if pos == 3 { - return IP{}, parseIPError{in: s, msg: "IPv4 address too long"} - } - fields[pos] = uint8(val) - pos++ - val = 0 - } else { - return IP{}, parseIPError{in: s, msg: "unexpected character", at: s[i:]} - } - } - if pos < 3 { - return IP{}, parseIPError{in: s, msg: "IPv4 address too short"} - } - return IPv4(fields[0], fields[1], fields[2], uint8(val)), nil -} - -// parseIPv6 parses s as an IPv6 address (in form "2001:db8::68"). -func parseIPv6(in string) (IP, error) { - s := in - - // Split off the zone right from the start. Yes it's a second scan - // of the string, but trying to handle it inline makes a bunch of - // other inner loop conditionals more expensive, and it ends up - // being slower. - zone := "" - i := strings.IndexByte(s, '%') - if i != -1 { - s, zone = s[:i], s[i+1:] - if zone == "" { - // Not allowed to have an empty zone if explicitly specified. - return IP{}, parseIPError{in: in, msg: "zone must be a non-empty string"} - } - } - - var ip [16]byte - ellipsis := -1 // position of ellipsis in ip - - // Might have leading ellipsis - if len(s) >= 2 && s[0] == ':' && s[1] == ':' { - ellipsis = 0 - s = s[2:] - // Might be only ellipsis - if len(s) == 0 { - return IPv6Unspecified().WithZone(zone), nil - } - } - - // Loop, parsing hex numbers followed by colon. - i = 0 - for i < 16 { - // Hex number. Similar to parseIPv4, inlining the hex number - // parsing yields a significant performance increase. - off := 0 - acc := uint32(0) - for ; off < len(s); off++ { - c := s[off] - if c >= '0' && c <= '9' { - acc = (acc << 4) + uint32(c-'0') - } else if c >= 'a' && c <= 'f' { - acc = (acc << 4) + uint32(c-'a'+10) - } else if c >= 'A' && c <= 'F' { - acc = (acc << 4) + uint32(c-'A'+10) - } else { - break - } - if acc > math.MaxUint16 { - // Overflow, fail. - return IP{}, parseIPError{in: in, msg: "IPv6 field has value >=2^16", at: s} - } - } - if off == 0 { - // No digits found, fail. - return IP{}, parseIPError{in: in, msg: "each colon-separated field must have at least one digit", at: s} - } - - // If followed by dot, might be in trailing IPv4. - if off < len(s) && s[off] == '.' { - if ellipsis < 0 && i != 12 { - // Not the right place. - return IP{}, parseIPError{in: in, msg: "embedded IPv4 address must replace the final 2 fields of the address", at: s} - } - if i+4 > 16 { - // Not enough room. - return IP{}, parseIPError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s} - } - // TODO: could make this a bit faster by having a helper - // that parses to a [4]byte, and have both parseIPv4 and - // parseIPv6 use it. - ip4, err := parseIPv4(s) - if err != nil { - return IP{}, parseIPError{in: in, msg: err.Error(), at: s} - } - ip[i] = ip4.v4(0) - ip[i+1] = ip4.v4(1) - ip[i+2] = ip4.v4(2) - ip[i+3] = ip4.v4(3) - s = "" - i += 4 - break - } - - // Save this 16-bit chunk. - ip[i] = byte(acc >> 8) - ip[i+1] = byte(acc) - i += 2 - - // Stop at end of string. - s = s[off:] - if len(s) == 0 { - break - } - - // Otherwise must be followed by colon and more. - if s[0] != ':' { - return IP{}, parseIPError{in: in, msg: "unexpected character, want colon", at: s} - } else if len(s) == 1 { - return IP{}, parseIPError{in: in, msg: "colon must be followed by more characters", at: s} - } - s = s[1:] - - // Look for ellipsis. - if s[0] == ':' { - if ellipsis >= 0 { // already have one - return IP{}, parseIPError{in: in, msg: "multiple :: in address", at: s} - } - ellipsis = i - s = s[1:] - if len(s) == 0 { // can be at end - break - } - } - } - - // Must have used entire string. - if len(s) != 0 { - return IP{}, parseIPError{in: in, msg: "trailing garbage after address", at: s} - } - - // If didn't parse enough, expand ellipsis. - if i < 16 { - if ellipsis < 0 { - return IP{}, parseIPError{in: in, msg: "address string too short"} - } - n := 16 - i - for j := i - 1; j >= ellipsis; j-- { - ip[j+n] = ip[j] - } - for j := ellipsis + n - 1; j >= ellipsis; j-- { - ip[j] = 0 - } - } else if ellipsis >= 0 { - // Ellipsis must represent at least one 0 group. - return IP{}, parseIPError{in: in, msg: "the :: must expand to at least one field of zeros"} - } - return IPv6Raw(ip).WithZone(zone), nil -} - -// FromStdIP returns an IP from the standard library's IP type. -// -// If std is invalid, ok is false. -// -// FromStdIP implicitly unmaps IPv6-mapped IPv4 addresses. That is, if -// len(std) == 16 and contains an IPv4 address, only the IPv4 part is -// returned, without the IPv6 wrapper. This is the common form returned by -// the standard library's ParseIP: https://play.golang.org/p/qdjylUkKWxl. -// To convert a standard library IP without the implicit unmapping, use -// FromStdIPRaw. -func FromStdIP(std net.IP) (ip IP, ok bool) { - ret, ok := FromStdIPRaw(std) - if ret.Is4in6() { - ret.z = z4 - } - return ret, ok -} - -// FromStdIPRaw returns an IP from the standard library's IP type. -// If std is invalid, ok is false. -// Unlike FromStdIP, FromStdIPRaw does not do an implicit Unmap if -// len(std) == 16 and contains an IPv6-mapped IPv4 address. -func FromStdIPRaw(std net.IP) (ip IP, ok bool) { - switch len(std) { - case 4: - return IPv4(std[0], std[1], std[2], std[3]), true - case 16: - return ipv6Slice(std), true - } - return IP{}, false -} - -// v4 returns the i'th byte of ip. If ip is not an IPv4, v4 returns -// unspecified garbage. -func (ip IP) v4(i uint8) uint8 { - return uint8(ip.addr.lo >> ((3 - i) * 8)) -} - -// v6 returns the i'th byte of ip. If ip is an IPv4 address, this -// accesses the IPv4-mapped IPv6 address form of the IP. -func (ip IP) v6(i uint8) uint8 { - return uint8(*(ip.addr.halves()[(i/8)%2]) >> ((7 - i%8) * 8)) -} - -// v6u16 returns the i'th 16-bit word of ip. If ip is an IPv4 address, -// this accesses the IPv4-mapped IPv6 address form of the IP. -func (ip IP) v6u16(i uint8) uint16 { - return uint16(*(ip.addr.halves()[(i/4)%2]) >> ((3 - i%4) * 16)) -} - -// IsZero reports whether ip is the zero value of the IP type. -// The zero value is not a valid IP address of any type. -// -// Note that "0.0.0.0" and "::" are not the zero value. Use IsUnspecified to -// check for these values instead. -func (ip IP) IsZero() bool { - // Faster than comparing ip == IP{}, but effectively equivalent, - // as there's no way to make an IP with a nil z from this package. - return ip.z == z0 -} - -// IsValid whether the IP is an initialized value and not the IP -// type's zero value. -// -// Note that both "0.0.0.0" and "::" are valid, non-zero values. -func (ip IP) IsValid() bool { return ip.z != z0 } - -// BitLen returns the number of bits in the IP address: -// 32 for IPv4 or 128 for IPv6. -// For the zero value (see IP.IsZero), it returns 0. -// For IP4-mapped IPv6 addresses, it returns 128. -func (ip IP) BitLen() uint8 { - switch ip.z { - case z0: - return 0 - case z4: - return 32 - } - return 128 -} - -// Zone returns ip's IPv6 scoped addressing zone, if any. -func (ip IP) Zone() string { - if ip.z == nil { - return "" - } - zone, _ := ip.z.Get().(string) - return zone -} - -// Compare returns an integer comparing two IPs. -// The result will be 0 if ip==ip2, -1 if ip < ip2, and +1 if ip > ip2. -// The definition of "less than" is the same as the IP.Less method. -func (ip IP) Compare(ip2 IP) int { - f1, f2 := ip.BitLen(), ip2.BitLen() - if f1 < f2 { - return -1 - } - if f1 > f2 { - return 1 - } - if hi1, hi2 := ip.addr.hi, ip2.addr.hi; hi1 < hi2 { - return -1 - } else if hi1 > hi2 { - return 1 - } - if lo1, lo2 := ip.addr.lo, ip2.addr.lo; lo1 < lo2 { - return -1 - } else if lo1 > lo2 { - return 1 - } - if ip.Is6() { - za, zb := ip.Zone(), ip2.Zone() - if za < zb { - return -1 - } else if za > zb { - return 1 - } - } - return 0 -} - -// Less reports whether ip sorts before ip2. -// IP addresses sort first by length, then their address. -// IPv6 addresses with zones sort just after the same address without a zone. -func (ip IP) Less(ip2 IP) bool { return ip.Compare(ip2) == -1 } - -func (ip IP) lessOrEq(ip2 IP) bool { return ip.Compare(ip2) <= 0 } - -// ipZone returns the standard library net.IP from ip, as well -// as the zone. -// The optional reuse IP provides memory to reuse. -func (ip IP) ipZone(reuse net.IP) (stdIP net.IP, zone string) { - base := reuse[:0] - switch { - case ip.z == z0: - return nil, "" - case ip.Is4(): - a4 := ip.As4() - return append(base, a4[:]...), "" - default: - a16 := ip.As16() - return append(base, a16[:]...), ip.Zone() - } -} - -// IPAddr returns the net.IPAddr representation of an IP. The returned value is -// always non-nil, but the IPAddr.IP will be nil if ip is the zero value. -// If ip contains a zone identifier, IPAddr.Zone is populated. -func (ip IP) IPAddr() *net.IPAddr { - stdIP, zone := ip.ipZone(nil) - return &net.IPAddr{IP: stdIP, Zone: zone} -} - -// Is4 reports whether ip is an IPv4 address. -// -// It returns false for IP4-mapped IPv6 addresses. See IP.Unmap. -func (ip IP) Is4() bool { - return ip.z == z4 -} - -// Is4in6 reports whether ip is an IPv4-mapped IPv6 address. -func (ip IP) Is4in6() bool { - return ip.Is6() && ip.addr.hi == 0 && ip.addr.lo>>32 == 0xffff -} - -// Is6 reports whether ip is an IPv6 address, including IPv4-mapped -// IPv6 addresses. -func (ip IP) Is6() bool { - return ip.z != z0 && ip.z != z4 -} - -// Unmap returns ip with any IPv4-mapped IPv6 address prefix removed. -// -// That is, if ip is an IPv6 address wrapping an IPv4 adddress, it -// returns the wrapped IPv4 address. Otherwise it returns ip, regardless -// of its type. -func (ip IP) Unmap() IP { - if ip.Is4in6() { - ip.z = z4 - } - return ip -} - -// WithZone returns an IP that's the same as ip but with the provided -// zone. If zone is empty, the zone is removed. If ip is an IPv4 -// address it's returned unchanged. -func (ip IP) WithZone(zone string) IP { - if !ip.Is6() { - return ip - } - if zone == "" { - ip.z = z6noz - return ip - } - ip.z = intern.GetByString(zone) - return ip -} - -// noZone unconditionally strips the zone from IP. -// It's similar to WithZone, but small enough to be inlinable. -func (ip IP) withoutZone() IP { - if !ip.Is6() { - return ip - } - ip.z = z6noz - return ip -} - -// hasZone reports whether IP has an IPv6 zone. -func (ip IP) hasZone() bool { - return ip.z != z0 && ip.z != z4 && ip.z != z6noz -} - -// IsLinkLocalUnicast reports whether ip is a link-local unicast address. -// If ip is the zero value, it will return false. -func (ip IP) IsLinkLocalUnicast() bool { - // Dynamic Configuration of IPv4 Link-Local Addresses - // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1 - if ip.Is4() { - return ip.v4(0) == 169 && ip.v4(1) == 254 - } - // IP Version 6 Addressing Architecture (2.4 Address Type Identification) - // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4 - if ip.Is6() { - return ip.v6u16(0)&0xffc0 == 0xfe80 - } - return false // zero value -} - -// IsLoopback reports whether ip is a loopback address. If ip is the zero value, -// it will return false. -func (ip IP) IsLoopback() bool { - // Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing) - // https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3 - if ip.Is4() { - return ip.v4(0) == 127 - } - // IP Version 6 Addressing Architecture (2.4 Address Type Identification) - // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4 - if ip.Is6() { - return ip.addr.hi == 0 && ip.addr.lo == 1 - } - return false // zero value -} - -// IsMulticast reports whether ip is a multicast address. If ip is the zero -// value, it will return false. -func (ip IP) IsMulticast() bool { - // Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES) - // https://datatracker.ietf.org/doc/html/rfc1112#section-4 - if ip.Is4() { - return ip.v4(0)&0xf0 == 0xe0 - } - // IP Version 6 Addressing Architecture (2.4 Address Type Identification) - // https://datatracker.ietf.org/doc/html/rfc4291#section-2.4 - if ip.Is6() { - return ip.addr.hi>>(64-8) == 0xff // ip.v6(0) == 0xff - } - return false // zero value -} - -// IsInterfaceLocalMulticast reports whether ip is an IPv6 interface-local -// multicast address. If ip is the zero value or an IPv4 address, it will return -// false. -func (ip IP) IsInterfaceLocalMulticast() bool { - // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses) - // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 - if ip.Is6() { - return ip.v6u16(0)&0xff0f == 0xff01 - } - return false // zero value -} - -// IsLinkLocalMulticast reports whether ip is a link-local multicast address. -// If ip is the zero value, it will return false. -func (ip IP) IsLinkLocalMulticast() bool { - // IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24)) - // https://datatracker.ietf.org/doc/html/rfc5771#section-4 - if ip.Is4() { - return ip.v4(0) == 224 && ip.v4(1) == 0 && ip.v4(2) == 0 - } - // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses) - // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 - if ip.Is6() { - return ip.v6u16(0)&0xff0f == 0xff02 - } - return false // zero value -} - -// IsGlobalUnicast reports whether ip is a global unicast address. -// -// It returns true for IPv6 addresses which fall outside of the current -// IANA-allocated 2000::/3 global unicast space, with the exception of the -// link-local address space. It also returns true even if ip is in the IPv4 -// private address space or IPv6 unique local address space. If ip is the zero -// value, it will return false. -// -// For reference, see RFC 1122, RFC 4291, and RFC 4632. -func (ip IP) IsGlobalUnicast() bool { - if ip.z == z0 { - // Invalid or zero-value. - return false - } - - // Match the stdlib's IsGlobalUnicast logic. Notably private IPv4 addresses - // and ULA IPv6 addresses are still considered "global unicast". - if ip.Is4() && (ip == IPv4(0, 0, 0, 0) || ip == IPv4(255, 255, 255, 255)) { - return false - } - - return ip != IPv6Unspecified() && - !ip.IsLoopback() && - !ip.IsMulticast() && - !ip.IsLinkLocalUnicast() -} - -// IsPrivate reports whether ip is a private address, according to RFC 1918 -// (IPv4 addresses) and RFC 4193 (IPv6 addresses). That is, it reports whether -// ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the -// same as the standard library's net.IP.IsPrivate. -func (ip IP) IsPrivate() bool { - // Match the stdlib's IsPrivate logic. - if ip.Is4() { - // RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as - // private IPv4 address subnets. - return ip.v4(0) == 10 || - (ip.v4(0) == 172 && ip.v4(1)&0xf0 == 16) || - (ip.v4(0) == 192 && ip.v4(1) == 168) - } - - if ip.Is6() { - // RFC 4193 allocates fc00::/7 as the unique local unicast IPv6 address - // subnet. - return ip.v6(0)&0xfe == 0xfc - } - - return false // zero value -} - -// IsUnspecified reports whether ip is an unspecified address, either the IPv4 -// address "0.0.0.0" or the IPv6 address "::". -// -// Note that the IP zero value is not an unspecified address. Use IsZero to -// check for the zero value instead. -func (ip IP) IsUnspecified() bool { - return ip == IPv4(0, 0, 0, 0) || ip == IPv6Unspecified() -} - -// Prefix applies a CIDR mask of leading bits to IP, producing an IPPrefix -// of the specified length. If IP is the zero value, a zero-value IPPrefix and -// a nil error are returned. If bits is larger than 32 for an IPv4 address or -// 128 for an IPv6 address, an error is returned. -func (ip IP) Prefix(bits uint8) (IPPrefix, error) { - effectiveBits := bits - switch ip.z { - case z0: - return IPPrefix{}, nil - case z4: - if bits > 32 { - return IPPrefix{}, fmt.Errorf("prefix length %d too large for IPv4", bits) - } - effectiveBits += 96 - default: - if bits > 128 { - return IPPrefix{}, fmt.Errorf("prefix length %d too large for IPv6", bits) - } - } - ip.addr = ip.addr.and(mask6[effectiveBits]) - return IPPrefixFrom(ip, bits), nil -} - -// Netmask applies a bit mask to IP, producing an IPPrefix. If IP is the -// zero value, a zero-value IPPrefix and a nil error are returned. If the -// netmask length is not 4 for IPv4 or 16 for IPv6, an error is -// returned. If the netmask is non-contiguous, an error is returned. -func (ip IP) Netmask(mask []byte) (IPPrefix, error) { - l := len(mask) - - switch ip.z { - case z0: - return IPPrefix{}, nil - case z4: - if l != net.IPv4len { - return IPPrefix{}, fmt.Errorf("netmask length %d incorrect for IPv4", l) - } - default: - if l != net.IPv6len { - return IPPrefix{}, fmt.Errorf("netmask length %d incorrect for IPv6", l) - } - } - - ones, bits := net.IPMask(mask).Size() - if ones == 0 && bits == 0 { - return IPPrefix{}, errors.New("netmask is non-contiguous") - } - - return ip.Prefix(uint8(ones)) -} - -// As16 returns the IP address in its 16 byte representation. -// IPv4 addresses are returned in their v6-mapped form. -// IPv6 addresses with zones are returned without their zone (use the -// Zone method to get it). -// The ip zero value returns all zeroes. -func (ip IP) As16() [16]byte { - var ret [16]byte - binary.BigEndian.PutUint64(ret[:8], ip.addr.hi) - binary.BigEndian.PutUint64(ret[8:], ip.addr.lo) - return ret -} - -// As4 returns an IPv4 or IPv4-in-IPv6 address in its 4 byte representation. -// If ip is the IP zero value or an IPv6 address, As4 panics. -// Note that 0.0.0.0 is not the zero value. -func (ip IP) As4() [4]byte { - if ip.z == z4 || ip.Is4in6() { - var ret [4]byte - binary.BigEndian.PutUint32(ret[:], uint32(ip.addr.lo)) - return ret - } - if ip.z == z0 { - panic("As4 called on IP zero value") - } - panic("As4 called on IPv6 address") -} - -// Next returns the IP following ip. -// If there is none, it returns the IP zero value. -func (ip IP) Next() IP { - ip.addr = ip.addr.addOne() - if ip.Is4() { - if uint32(ip.addr.lo) == 0 { - // Overflowed. - return IP{} - } - } else { - if ip.addr.isZero() { - // Overflowed - return IP{} - } - } - return ip -} - -// Prior returns the IP before ip. -// If there is none, it returns the IP zero value. -func (ip IP) Prior() IP { - if ip.Is4() { - if uint32(ip.addr.lo) == 0 { - return IP{} - } - } else if ip.addr.isZero() { - return IP{} - } - ip.addr = ip.addr.subOne() - return ip -} - -// String returns the string form of the IP address ip. -// It returns one of 4 forms: -// -// - "invalid IP", if ip is the zero value -// - IPv4 dotted decimal ("192.0.2.1") -// - IPv6 ("2001:db8::1") -// - IPv6 with zone ("fe80:db8::1%eth0") -// -// Note that unlike the Go standard library's IP.String method, -// IP4-mapped IPv6 addresses do not format as dotted decimals. -func (ip IP) String() string { - switch ip.z { - case z0: - return "zero IP" - case z4: - return ip.string4() - default: - return ip.string6() - } -} - -// AppendTo appends a text encoding of ip, -// as generated by MarshalText, -// to b and returns the extended buffer. -func (ip IP) AppendTo(b []byte) []byte { - switch ip.z { - case z0: - return b - case z4: - return ip.appendTo4(b) - default: - return ip.appendTo6(b) - } -} - -// digits is a string of the hex digits from 0 to f. It's used in -// appendDecimal and appendHex to format IP addresses. -const digits = "0123456789abcdef" - -// appendDecimal appends the decimal string representation of x to b. -func appendDecimal(b []byte, x uint8) []byte { - // Using this function rather than strconv.AppendUint makes IPv4 - // string building 2x faster. - - if x >= 100 { - b = append(b, digits[x/100]) - } - if x >= 10 { - b = append(b, digits[x/10%10]) - } - return append(b, digits[x%10]) -} - -// appendHex appends the hex string representation of x to b. -func appendHex(b []byte, x uint16) []byte { - // Using this function rather than strconv.AppendUint makes IPv6 - // string building 2x faster. - - if x >= 0x1000 { - b = append(b, digits[x>>12]) - } - if x >= 0x100 { - b = append(b, digits[x>>8&0xf]) - } - if x >= 0x10 { - b = append(b, digits[x>>4&0xf]) - } - return append(b, digits[x&0xf]) -} - -// appendHexPad appends the fully padded hex string representation of x to b. -func appendHexPad(b []byte, x uint16) []byte { - return append(b, digits[x>>12], digits[x>>8&0xf], digits[x>>4&0xf], digits[x&0xf]) -} - -func (ip IP) string4() string { - const max = len("255.255.255.255") - ret := make([]byte, 0, max) - ret = ip.appendTo4(ret) - return string(ret) -} - -func (ip IP) appendTo4(ret []byte) []byte { - ret = appendDecimal(ret, ip.v4(0)) - ret = append(ret, '.') - ret = appendDecimal(ret, ip.v4(1)) - ret = append(ret, '.') - ret = appendDecimal(ret, ip.v4(2)) - ret = append(ret, '.') - ret = appendDecimal(ret, ip.v4(3)) - return ret -} - -// string6 formats ip in IPv6 textual representation. It follows the -// guidelines in section 4 of RFC 5952 -// (https://tools.ietf.org/html/rfc5952#section-4): no unnecessary -// zeros, use :: to elide the longest run of zeros, and don't use :: -// to compact a single zero field. -func (ip IP) string6() string { - // Use a zone with a "plausibly long" name, so that most zone-ful - // IP addresses won't require additional allocation. - // - // The compiler does a cool optimization here, where ret ends up - // stack-allocated and so the only allocation this function does - // is to construct the returned string. As such, it's okay to be a - // bit greedy here, size-wise. - const max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") - ret := make([]byte, 0, max) - ret = ip.appendTo6(ret) - return string(ret) -} - -func (ip IP) appendTo6(ret []byte) []byte { - zeroStart, zeroEnd := uint8(255), uint8(255) - for i := uint8(0); i < 8; i++ { - j := i - for j < 8 && ip.v6u16(j) == 0 { - j++ - } - if l := j - i; l >= 2 && l > zeroEnd-zeroStart { - zeroStart, zeroEnd = i, j - } - } - - for i := uint8(0); i < 8; i++ { - if i == zeroStart { - ret = append(ret, ':', ':') - i = zeroEnd - if i >= 8 { - break - } - } else if i > 0 { - ret = append(ret, ':') - } - - ret = appendHex(ret, ip.v6u16(i)) - } - - if ip.z != z6noz { - ret = append(ret, '%') - ret = append(ret, ip.Zone()...) - } - return ret -} - -// StringExpanded is like String but IPv6 addresses are expanded with leading -// zeroes and no "::" compression. For example, "2001:db8::1" becomes -// "2001:0db8:0000:0000:0000:0000:0000:0001". -func (ip IP) StringExpanded() string { - switch ip.z { - case z0, z4: - return ip.String() - } - - const size = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") - ret := make([]byte, 0, size) - for i := uint8(0); i < 8; i++ { - if i > 0 { - ret = append(ret, ':') - } - - ret = appendHexPad(ret, ip.v6u16(i)) - } - - if ip.z != z6noz { - // The addition of a zone will cause a second allocation, but when there - // is no zone the ret slice will be stack allocated. - ret = append(ret, '%') - ret = append(ret, ip.Zone()...) - } - return string(ret) -} - -// MarshalText implements the encoding.TextMarshaler interface, -// The encoding is the same as returned by String, with one exception: -// If ip is the zero value, the encoding is the empty string. -func (ip IP) MarshalText() ([]byte, error) { - switch ip.z { - case z0: - return []byte(""), nil - case z4: - max := len("255.255.255.255") - b := make([]byte, 0, max) - return ip.appendTo4(b), nil - default: - max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") - b := make([]byte, 0, max) - return ip.appendTo6(b), nil - } -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// The IP address is expected in a form accepted by ParseIP. -// It returns an error if *ip is not the IP zero value. -func (ip *IP) UnmarshalText(text []byte) error { - if ip.z != z0 { - return errors.New("refusing to Unmarshal into non-zero IP") - } - if len(text) == 0 { - return nil - } - var err error - *ip, err = ParseIP(string(text)) - return err -} - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (ip IP) MarshalBinary() ([]byte, error) { - switch ip.z { - case z0: - return nil, nil - case z4: - b := ip.As4() - return b[:], nil - default: - b16 := ip.As16() - b := b16[:] - if z := ip.Zone(); z != "" { - b = append(b, []byte(z)...) - } - return b, nil - } -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -func (ip *IP) UnmarshalBinary(b []byte) error { - if ip.z != z0 { - return errors.New("refusing to Unmarshal into non-zero IP") - } - n := len(b) - switch { - case n == 0: - return nil - case n == 4: - *ip = IPv4(b[0], b[1], b[2], b[3]) - return nil - case n == 16: - *ip = ipv6Slice(b) - return nil - case n > 16: - *ip = ipv6Slice(b[:16]).WithZone(string(b[16:])) - return nil - } - return fmt.Errorf("unexpected ip size: %v", len(b)) -} - -// IPPort is an IP and a port number. -type IPPort struct { - ip IP - port uint16 -} - -// IPPortFrom returns an IPPort with IP ip and port port. -// It does not allocate. -func IPPortFrom(ip IP, port uint16) IPPort { return IPPort{ip: ip, port: port} } - -// WithIP returns an IPPort with IP ip and port p.Port(). -func (p IPPort) WithIP(ip IP) IPPort { return IPPort{ip: ip, port: p.port} } - -// WithIP returns an IPPort with IP p.IP() and port port. -func (p IPPort) WithPort(port uint16) IPPort { return IPPort{ip: p.ip, port: port} } - -// IP returns p's IP. -func (p IPPort) IP() IP { return p.ip } - -// Port returns p's port. -func (p IPPort) Port() uint16 { return p.port } - -// splitIPPort splits s into an IP address string and a port -// string. It splits strings shaped like "foo:bar" or "[foo]:bar", -// without further validating the substrings. v6 indicates whether the -// ip string should parse as an IPv6 address or an IPv4 address, in -// order for s to be a valid ip:port string. -func splitIPPort(s string) (ip, port string, v6 bool, err error) { - i := strings.LastIndexByte(s, ':') - if i == -1 { - return "", "", false, errors.New("not an ip:port") - } - - ip, port = s[:i], s[i+1:] - if len(ip) == 0 { - return "", "", false, errors.New("no IP") - } - if len(port) == 0 { - return "", "", false, errors.New("no port") - } - if ip[0] == '[' { - if len(ip) < 2 || ip[len(ip)-1] != ']' { - return "", "", false, errors.New("missing ]") - } - ip = ip[1 : len(ip)-1] - v6 = true - } - - return ip, port, v6, nil -} - -// ParseIPPort parses s as an IPPort. -// -// It doesn't do any name resolution, and ports must be numeric. -func ParseIPPort(s string) (IPPort, error) { - var ipp IPPort - ip, port, v6, err := splitIPPort(s) - if err != nil { - return ipp, err - } - port16, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return ipp, fmt.Errorf("invalid port %q parsing %q", port, s) - } - ipp.port = uint16(port16) - ipp.ip, err = ParseIP(ip) - if err != nil { - return IPPort{}, err - } - if v6 && ipp.ip.Is4() { - return IPPort{}, fmt.Errorf("invalid ip:port %q, square brackets can only be used with IPv6 addresses", s) - } else if !v6 && ipp.ip.Is6() { - return IPPort{}, fmt.Errorf("invalid ip:port %q, IPv6 addresses must be surrounded by square brackets", s) - } - return ipp, nil -} - -// MustParseIPPort calls ParseIPPort(s) and panics on error. -// It is intended for use in tests with hard-coded strings. -func MustParseIPPort(s string) IPPort { - ip, err := ParseIPPort(s) - if err != nil { - panic(err) - } - return ip -} - -// IsZero reports whether p is its zero value. -func (p IPPort) IsZero() bool { return p == IPPort{} } - -// IsValid reports whether p.IP() is valid. -// All ports are valid, including zero. -func (p IPPort) IsValid() bool { return p.ip.IsValid() } - -// Valid reports whether p.IP() is valid. -// All ports are valid, including zero. -// -// Deprecated: use the correctly named and identical IsValid method instead. -func (p IPPort) Valid() bool { return p.IsValid() } - -func (p IPPort) String() string { - switch p.ip.z { - case z0: - return "invalid IPPort" - case z4: - a := p.ip.As4() - return fmt.Sprintf("%d.%d.%d.%d:%d", a[0], a[1], a[2], a[3], p.port) - default: - // TODO: this could be more efficient allocation-wise: - return net.JoinHostPort(p.ip.String(), strconv.Itoa(int(p.port))) - } -} - -// AppendTo appends a text encoding of p, -// as generated by MarshalText, -// to b and returns the extended buffer. -func (p IPPort) AppendTo(b []byte) []byte { - switch p.ip.z { - case z0: - return b - case z4: - b = p.ip.appendTo4(b) - default: - b = append(b, '[') - b = p.ip.appendTo6(b) - b = append(b, ']') - } - b = append(b, ':') - b = strconv.AppendInt(b, int64(p.port), 10) - return b -} - -// MarshalText implements the encoding.TextMarshaler interface. The -// encoding is the same as returned by String, with one exception: if -// p.IP() is the zero value, the encoding is the empty string. -func (p IPPort) MarshalText() ([]byte, error) { - var max int - switch p.ip.z { - case z0: - case z4: - max = len("255.255.255.255:65535") - default: - max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535") - } - b := make([]byte, 0, max) - b = p.AppendTo(b) - return b, nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler -// interface. The IPPort is expected in a form accepted by -// ParseIPPort. It returns an error if *p is not the IPPort zero -// value. -func (p *IPPort) UnmarshalText(text []byte) error { - if p.ip.z != z0 || p.port != 0 { - return errors.New("refusing to Unmarshal into non-zero IPPort") - } - if len(text) == 0 { - return nil - } - var err error - *p, err = ParseIPPort(string(text)) - return err -} - -// FromStdAddr maps the components of a standard library TCPAddr or -// UDPAddr into an IPPort. -func FromStdAddr(stdIP net.IP, port int, zone string) (_ IPPort, ok bool) { - ip, ok := FromStdIP(stdIP) - if !ok || port < 0 || port > math.MaxUint16 { - return - } - ip = ip.Unmap() - if zone != "" { - if ip.Is4() { - ok = false - return - } - ip = ip.WithZone(zone) - } - return IPPort{ip: ip, port: uint16(port)}, true -} - -// UDPAddr returns a standard library net.UDPAddr from p. -// The returned value is always non-nil. If p.IP() is the zero -// value, then UDPAddr.IP is nil. -// -// UDPAddr necessarily does two allocations. If you have an existing -// UDPAddr already allocated, see UDPAddrAt. -func (p IPPort) UDPAddr() *net.UDPAddr { - ret := &net.UDPAddr{ - Port: int(p.port), - } - ret.IP, ret.Zone = p.ip.ipZone(nil) - return ret -} - -// UDPAddrAt is like UDPAddr, but reuses the provided UDPAddr, which -// must be non-nil. If at.IP has a capacity of 16, UDPAddrAt is -// allocation-free. It returns at to facilitate using this method as a -// wrapper. -func (p IPPort) UDPAddrAt(at *net.UDPAddr) *net.UDPAddr { - at.Port = int(p.port) - at.IP, at.Zone = p.ip.ipZone(at.IP) - return at -} - -// TCPAddr returns a standard library net.TCPAddr from p. -// The returned value is always non-nil. If p.IP() is the zero -// value, then TCPAddr.IP is nil. -func (p IPPort) TCPAddr() *net.TCPAddr { - ip, zone := p.ip.ipZone(nil) - return &net.TCPAddr{ - IP: ip, - Port: int(p.port), - Zone: zone, - } -} - -// IPPrefix is an IP address prefix (CIDR) representing an IP network. -// -// The first Bits() of IP() are specified. The remaining bits match any address. -// The range of Bits() is [0,32] for IPv4 or [0,128] for IPv6. -type IPPrefix struct { - ip IP - bits uint8 -} - -// IPPrefixFrom returns an IPPrefix with IP ip and provided bits prefix length. -// It does not allocate. -func IPPrefixFrom(ip IP, bits uint8) IPPrefix { - return IPPrefix{ - ip: ip.withoutZone(), - bits: bits, - } -} - -// IP returns p's IP. -func (p IPPrefix) IP() IP { return p.ip } - -// Bits returns p's prefix length. -func (p IPPrefix) Bits() uint8 { return p.bits } - -// IsValid reports whether whether p.Bits() has a valid range for p.IP(). -// If p.IP() is zero, Valid returns false. -func (p IPPrefix) IsValid() bool { return !p.ip.IsZero() && p.bits <= p.ip.BitLen() } - -// Valid reports whether whether p.Bits() has a valid range for p.IP(). -// If p.IP() is zero, Valid returns false. -// -// Deprecated: use the correctly named and identical IsValid method instead. -func (p IPPrefix) Valid() bool { return p.IsValid() } - -// IsZero reports whether p is its zero value. -func (p IPPrefix) IsZero() bool { return p == IPPrefix{} } - -// IsSingleIP reports whether p contains exactly one IP. -func (p IPPrefix) IsSingleIP() bool { return p.bits != 0 && p.bits == p.ip.BitLen() } - -// FromStdIPNet returns an IPPrefix from the standard library's IPNet type. -// If std is invalid, ok is false. -func FromStdIPNet(std *net.IPNet) (prefix IPPrefix, ok bool) { - ip, ok := FromStdIP(std.IP) - if !ok { - return IPPrefix{}, false - } - - if l := len(std.Mask); l != net.IPv4len && l != net.IPv6len { - // Invalid mask. - return IPPrefix{}, false - } - - ones, bits := std.Mask.Size() - if ones == 0 && bits == 0 { - // IPPrefix does not support non-contiguous masks. - return IPPrefix{}, false - } - - return IPPrefix{ - ip: ip, - bits: uint8(ones), - }, true -} - -// ParseIPPrefix parses s as an IP address prefix. -// The string can be in the form "192.168.1.0/24" or "2001::db8::/32", -// the CIDR notation defined in RFC 4632 and RFC 4291. -// -// Note that masked address bits are not zeroed. Use Masked for that. -func ParseIPPrefix(s string) (IPPrefix, error) { - i := strings.LastIndexByte(s, '/') - if i < 0 { - return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): no '/'", s) - } - ip, err := ParseIP(s[:i]) - if err != nil { - return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): %v", s, err) - } - s = s[i+1:] - bits, err := strconv.Atoi(s) - if err != nil { - return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): bad prefix: %v", s, err) - } - maxBits := 32 - if ip.Is6() { - maxBits = 128 - } - if bits < 0 || bits > maxBits { - return IPPrefix{}, fmt.Errorf("netaddr.ParseIPPrefix(%q): prefix length out of range", s) - } - return IPPrefixFrom(ip, uint8(bits)), nil -} - -// MustParseIPPrefix calls ParseIPPrefix(s) and panics on error. -// It is intended for use in tests with hard-coded strings. -func MustParseIPPrefix(s string) IPPrefix { - ip, err := ParseIPPrefix(s) - if err != nil { - panic(err) - } - return ip -} - -// Masked returns p in its canonical form, with bits of p.IP() not in p.Bits() masked off. -// If p is zero or otherwise invalid, Masked returns the zero value. -func (p IPPrefix) Masked() IPPrefix { - if m, err := p.ip.Prefix(p.bits); err == nil { - return m - } - return IPPrefix{} -} - -// Range returns the inclusive range of IPs that p covers. -// -// If p is zero or otherwise invalid, Range returns the zero value. -func (p IPPrefix) Range() IPRange { - p = p.Masked() - if p.IsZero() { - return IPRange{} - } - return IPRangeFrom(p.ip, p.lastIP()) -} - -// IPNet returns the net.IPNet representation of an IPPrefix. -// The returned value is always non-nil. -// Any zone identifier is dropped in the conversion. -func (p IPPrefix) IPNet() *net.IPNet { - if !p.IsValid() { - return &net.IPNet{} - } - stdIP, _ := p.ip.ipZone(nil) - return &net.IPNet{ - IP: stdIP, - Mask: net.CIDRMask(int(p.bits), int(p.ip.BitLen())), - } -} - -// Contains reports whether the network p includes ip. -// -// An IPv4 address will not match an IPv6 prefix. -// A v6-mapped IPv6 address will not match an IPv4 prefix. -// A zero-value IP will not match any prefix. -// If ip has an IPv6 zone, Contains returns false, -// because IPPrefixes strip zones. -func (p IPPrefix) Contains(ip IP) bool { - if !p.IsValid() || ip.hasZone() { - return false - } - if f1, f2 := p.ip.BitLen(), ip.BitLen(); f1 == 0 || f2 == 0 || f1 != f2 { - return false - } - if ip.Is4() { - // xor the IP addresses together; mismatched bits are now ones. - // Shift away the number of bits we don't care about. - // Shifts in Go are more efficient if the compiler can prove - // that the shift amount is smaller than the width of the shifted type (64 here). - // We know that p.bits is in the range 0..32 because p is Valid; - // the compiler doesn't know that, so mask with 63 to help it. - // Now truncate to 32 bits, because this is IPv4. - // If all the bits we care about are equal, the result will be zero. - return uint32((ip.addr.lo^p.ip.addr.lo)>>((32-p.bits)&63)) == 0 - } else { - // xor the IP addresses together. - // Mask away the bits we don't care about. - // If all the bits we care about are equal, the result will be zero. - return ip.addr.xor(p.ip.addr).and(mask6[p.bits]).isZero() - } -} - -// Overlaps reports whether p and o overlap at all. -// -// If p and o are of different address families or either have a zero -// IP, it reports false. Like the Contains method, a prefix with a -// v6-mapped IPv4 IP is still treated as an IPv6 mask. -// -// If either has a Bits of zero, it returns true. -func (p IPPrefix) Overlaps(o IPPrefix) bool { - if !p.IsValid() || !o.IsValid() { - return false - } - if p == o { - return true - } - if p.ip.Is4() != o.ip.Is4() { - return false - } - var minBits uint8 - if p.bits < o.bits { - minBits = p.bits - } else { - minBits = o.bits - } - if minBits == 0 { - return true - } - // One of these Prefix calls might look redundant, but we don't require - // that p and o values are normalized (via IPPrefix.Masked) first, - // so the Prefix call on the one that's already minBits serves to zero - // out any remaining bits in IP. - var err error - if p, err = p.ip.Prefix(minBits); err != nil { - return false - } - if o, err = o.ip.Prefix(minBits); err != nil { - return false - } - return p.ip == o.ip -} - -// AppendTo appends a text encoding of p, -// as generated by MarshalText, -// to b and returns the extended buffer. -func (p IPPrefix) AppendTo(b []byte) []byte { - if p.IsZero() { - return b - } - if !p.IsValid() { - return append(b, "invalid IPPrefix"...) - } - - // p.IP is non-zero, because p is valid. - if p.ip.z == z4 { - b = p.ip.appendTo4(b) - } else { - b = p.ip.appendTo6(b) - } - - b = append(b, '/') - b = appendDecimal(b, p.bits) - return b -} - -// MarshalText implements the encoding.TextMarshaler interface, -// The encoding is the same as returned by String, with one exception: -// If p is the zero value, the encoding is the empty string. -func (p IPPrefix) MarshalText() ([]byte, error) { - var max int - switch p.ip.z { - case z0: - case z4: - max = len("255.255.255.255/32") - default: - max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0/128") - } - b := make([]byte, 0, max) - b = p.AppendTo(b) - return b, nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// The IP address is expected in a form accepted by ParseIPPrefix. -// It returns an error if *p is not the IPPrefix zero value. -func (p *IPPrefix) UnmarshalText(text []byte) error { - if *p != (IPPrefix{}) { - return errors.New("refusing to Unmarshal into non-zero IPPrefix") - } - if len(text) == 0 { - return nil - } - var err error - *p, err = ParseIPPrefix(string(text)) - return err -} - -// String returns the CIDR notation of p: "/". -func (p IPPrefix) String() string { - if p.IsZero() { - return "zero IPPrefix" - } - if !p.IsValid() { - return "invalid IPPrefix" - } - return fmt.Sprintf("%s/%d", p.ip, p.bits) -} - -// lastIP returns the last IP in the prefix. -func (p IPPrefix) lastIP() IP { - if !p.IsValid() { - return IP{} - } - a16 := p.ip.As16() - var off uint8 - var bits uint8 = 128 - if p.ip.Is4() { - off = 12 - bits = 32 - } - for b := p.bits; b < bits; b++ { - byteNum, bitInByte := b/8, 7-(b%8) - a16[off+byteNum] |= 1 << uint(bitInByte) - } - if p.ip.Is4() { - return IPFrom16(a16) - } else { - return IPv6Raw(a16) // doesn't unmap - } -} - -// IPRange represents an inclusive range of IP addresses -// from the same address family. -// -// The From() and To() IPs are inclusive bounds, both included in the -// range. -// -// To be valid, the From() and To() values must be non-zero, have matching -// address families (IPv4 vs IPv6), and From() must be less than or equal to To(). -// IPv6 zones are stripped out and ignored. -// An invalid range may be ignored. -type IPRange struct { - // from is the initial IP address in the range. - from IP - - // to is the final IP address in the range. - to IP -} - -// IPRangeFrom returns an IPRange from from to to. -// It does not allocate. -func IPRangeFrom(from, to IP) IPRange { - return IPRange{ - from: from.withoutZone(), - to: to.withoutZone(), - } -} - -// From returns the lower bound of r. -func (r IPRange) From() IP { return r.from } - -// To returns the upper bound of r. -func (r IPRange) To() IP { return r.to } - -// ParseIPRange parses a range out of two IPs separated by a hyphen. -// -// It returns an error if the range is not valid. -func ParseIPRange(s string) (IPRange, error) { - var r IPRange - h := strings.IndexByte(s, '-') - if h == -1 { - return r, fmt.Errorf("no hyphen in range %q", s) - } - from, to := s[:h], s[h+1:] - var err error - r.from, err = ParseIP(from) - if err != nil { - return r, fmt.Errorf("invalid From IP %q in range %q", from, s) - } - r.from = r.from.withoutZone() - r.to, err = ParseIP(to) - if err != nil { - return r, fmt.Errorf("invalid To IP %q in range %q", to, s) - } - r.to = r.to.withoutZone() - if !r.IsValid() { - return r, fmt.Errorf("range %v to %v not valid", r.from, r.to) - } - return r, nil -} - -// MustParseIPRange calls ParseIPRange(s) and panics on error. -// It is intended for use in tests with hard-coded strings. -func MustParseIPRange(s string) IPRange { - r, err := ParseIPRange(s) - if err != nil { - panic(err) - } - return r -} - -// String returns a string representation of the range. -// -// For a valid range, the form is "From-To" with a single hyphen -// separating the IPs, the same format recognized by -// ParseIPRange. -func (r IPRange) String() string { - if r.IsValid() { - return fmt.Sprintf("%s-%s", r.from, r.to) - } - if r.from.IsZero() || r.to.IsZero() { - return "zero IPRange" - } - return "invalid IPRange" -} - -// AppendTo appends a text encoding of r, -// as generated by MarshalText, -// to b and returns the extended buffer. -func (r IPRange) AppendTo(b []byte) []byte { - if r.IsZero() { - return b - } - b = r.from.AppendTo(b) - b = append(b, '-') - b = r.to.AppendTo(b) - return b -} - -// MarshalText implements the encoding.TextMarshaler interface, -// The encoding is the same as returned by String, with one exception: -// If ip is the zero value, the encoding is the empty string. -func (r IPRange) MarshalText() ([]byte, error) { - if r.IsZero() { - return []byte(""), nil - } - var max int - if r.from.z == z4 { - max = len("255.255.255.255-255.255.255.255") - } else { - max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") - } - b := make([]byte, 0, max) - return r.AppendTo(b), nil -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// The IP range is expected in a form accepted by ParseIPRange. -// It returns an error if *r is not the IPRange zero value. -func (r *IPRange) UnmarshalText(text []byte) error { - if *r != (IPRange{}) { - return errors.New("refusing to Unmarshal into non-zero IPRange") - } - if len(text) == 0 { - return nil - } - var err error - *r, err = ParseIPRange(string(text)) - return err -} - -// IsZero reports whether r is the zero value of the IPRange type. -func (r IPRange) IsZero() bool { - return r == IPRange{} -} - -// IsValid reports whether r.From() and r.To() are both non-zero and -// obey the documented requirements: address families match, and From -// is less than or equal to To. -func (r IPRange) IsValid() bool { - return !r.from.IsZero() && - r.from.z == r.to.z && - !r.to.Less(r.from) -} - -// Valid reports whether r.From() and r.To() are both non-zero and -// obey the documented requirements: address families match, and From -// is less than or equal to To. -// -// Deprecated: use the correctly named and identical IsValid method instead. -func (r IPRange) Valid() bool { return r.IsValid() } - -// Contains reports whether the range r includes addr. -// -// An invalid range always reports false. -// -// If ip has an IPv6 zone, Contains returns false, -// because IPPrefixes strip zones. -func (r IPRange) Contains(addr IP) bool { - return r.IsValid() && !addr.hasZone() && r.contains(addr) -} - -// contains is like Contains, but without the validity check. -// addr must not have a zone. -func (r IPRange) contains(addr IP) bool { - return r.from.Compare(addr) <= 0 && r.to.Compare(addr) >= 0 -} - -// less reports whether r is "before" other. It is before if r.From() -// is before other.From(). If they're equal, then the larger range -// (higher To()) comes first. -func (r IPRange) less(other IPRange) bool { - if cmp := r.from.Compare(other.from); cmp != 0 { - return cmp < 0 - } - return other.to.Less(r.to) -} - -// entirelyBefore returns whether r lies entirely before other in IP -// space. -func (r IPRange) entirelyBefore(other IPRange) bool { - return r.to.Less(other.from) -} - -// entirelyWithin returns whether r is entirely contained within -// other. -func (r IPRange) coveredBy(other IPRange) bool { - return other.from.lessOrEq(r.from) && r.to.lessOrEq(other.to) -} - -// inMiddleOf returns whether r is inside other, but not touching the -// edges of other. -func (r IPRange) inMiddleOf(other IPRange) bool { - return other.from.Less(r.from) && r.to.Less(other.to) -} - -// overlapsStartOf returns whether r entirely overlaps the start of -// other, but not all of other. -func (r IPRange) overlapsStartOf(other IPRange) bool { - return r.from.lessOrEq(other.from) && r.to.Less(other.to) -} - -// overlapsEndOf returns whether r entirely overlaps the end of -// other, but not all of other. -func (r IPRange) overlapsEndOf(other IPRange) bool { - return other.from.Less(r.from) && other.to.lessOrEq(r.to) -} - -// mergeIPRanges returns the minimum and sorted set of IP ranges that -// cover r. -func mergeIPRanges(rr []IPRange) (out []IPRange, valid bool) { - // Always return a copy of r, to avoid aliasing slice memory in - // the caller. - switch len(rr) { - case 0: - return nil, true - case 1: - return []IPRange{rr[0]}, true - } - - sort.Slice(rr, func(i, j int) bool { return rr[i].less(rr[j]) }) - out = make([]IPRange, 1, len(rr)) - out[0] = rr[0] - for _, r := range rr[1:] { - prev := &out[len(out)-1] - switch { - case !r.IsValid(): - // Invalid ranges make no sense to merge, refuse to - // perform. - return nil, false - case prev.to.Next() == r.from: - // prev and r touch, merge them. - // - // prev r - // f------tf-----t - prev.to = r.to - case prev.to.Less(r.from): - // No overlap and not adjacent (per previous case), no - // merging possible. - // - // prev r - // f------t f-----t - out = append(out, r) - case prev.to.Less(r.to): - // Partial overlap, update prev - // - // prev - // f------t - // f-----t - // r - prev.to = r.to - default: - // r entirely contained in prev, nothing to do. - // - // prev - // f--------t - // f-----t - // r - } - } - return out, true -} - -// Overlaps reports whether p and o overlap at all. -// -// If p and o are of different address families or either are invalid, -// it reports false. -func (r IPRange) Overlaps(o IPRange) bool { - return r.IsValid() && - o.IsValid() && - r.from.Compare(o.to) <= 0 && - o.from.Compare(r.to) <= 0 -} - -// prefixMaker returns a address-family-corrected IPPrefix from a and bits, -// where the input bits is always in the IPv6-mapped form for IPv4 addresses. -type prefixMaker func(a uint128, bits uint8) IPPrefix - -// Prefixes returns the set of IPPrefix entries that covers r. -// -// If either of r's bounds are invalid, in the wrong order, or if -// they're of different address families, then Prefixes returns nil. -// -// Prefixes necessarily allocates. See AppendPrefixes for a version that uses -// memory you provide. -func (r IPRange) Prefixes() []IPPrefix { - return r.AppendPrefixes(nil) -} - -// AppendPrefixes is an append version of IPRange.Prefixes. It appends -// the IPPrefix entries that cover r to dst. -func (r IPRange) AppendPrefixes(dst []IPPrefix) []IPPrefix { - if !r.IsValid() { - return nil - } - return appendRangePrefixes(dst, r.prefixFrom128AndBits, r.from.addr, r.to.addr) -} - -func (r IPRange) prefixFrom128AndBits(a uint128, bits uint8) IPPrefix { - ip := IP{addr: a, z: r.from.z} - if r.from.Is4() { - bits -= 12 * 8 - } - return IPPrefix{ip, bits} -} - -// aZeroBSet is whether, after the common bits, a is all zero bits and -// b is all set (one) bits. -func comparePrefixes(a, b uint128) (common uint8, aZeroBSet bool) { - common = a.commonPrefixLen(b) - - // See whether a and b, after their common shared bits, end - // in all zero bits or all one bits, respectively. - if common == 128 { - return common, true - } - - m := mask6[common] - return common, (a.xor(a.and(m)).isZero() && - b.or(m) == uint128{^uint64(0), ^uint64(0)}) -} - -// Prefix returns r as an IPPrefix, if it can be presented exactly as such. -// If r is not valid or is not exactly equal to one prefix, ok is false. -func (r IPRange) Prefix() (p IPPrefix, ok bool) { - if !r.IsValid() { - return - } - if common, ok := comparePrefixes(r.from.addr, r.to.addr); ok { - return r.prefixFrom128AndBits(r.from.addr, common), true - } - return -} - -func appendRangePrefixes(dst []IPPrefix, makePrefix prefixMaker, a, b uint128) []IPPrefix { - common, ok := comparePrefixes(a, b) - if ok { - // a to b represents a whole range, like 10.50.0.0/16. - // (a being 10.50.0.0 and b being 10.50.255.255) - return append(dst, makePrefix(a, common)) - } - // Otherwise recursively do both halves. - dst = appendRangePrefixes(dst, makePrefix, a, a.bitsSetFrom(common+1)) - dst = appendRangePrefixes(dst, makePrefix, b.bitsClearedFrom(common+1), b) - return dst -} diff --git a/vendor/modules.txt b/vendor/modules.txt index a3b740a1..c87b175d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,8 +1,8 @@ # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/fatih/color v1.13.0 -## explicit; go 1.13 +# github.com/fatih/color v1.16.0 +## explicit; go 1.17 github.com/fatih/color # github.com/hashicorp/errwrap v1.1.0 ## explicit @@ -14,25 +14,25 @@ github.com/hashicorp/go-multierror ## explicit; go 1.15 github.com/ipinfo/go/v2/ipinfo github.com/ipinfo/go/v2/ipinfo/cache -# github.com/ipinfo/mmdbctl v0.0.0-20230726080357-558a20ba8524 +# github.com/ipinfo/mmdbctl v0.0.0-20231218070001-af3e28a7cd61 ## explicit; go 1.20 github.com/ipinfo/mmdbctl/lib # github.com/jszwec/csvutil v1.4.0 ## explicit; go 1.13 github.com/jszwec/csvutil -# github.com/mattn/go-colorable v0.1.9 -## explicit; go 1.13 +# github.com/mattn/go-colorable v0.1.13 +## explicit; go 1.15 github.com/mattn/go-colorable -# github.com/mattn/go-isatty v0.0.14 -## explicit; go 1.12 +# github.com/mattn/go-isatty v0.0.20 +## explicit; go 1.15 github.com/mattn/go-isatty -# github.com/maxmind/mmdbwriter v0.0.0-20220808142708-766ad8188582 -## explicit; go 1.17 +# github.com/maxmind/mmdbwriter v1.0.1-0.20231024181307-469cd9b959b4 +## explicit; go 1.20 github.com/maxmind/mmdbwriter github.com/maxmind/mmdbwriter/inserter github.com/maxmind/mmdbwriter/mmdbtype -# github.com/oschwald/maxminddb-golang v1.10.0 -## explicit; go 1.18 +# github.com/oschwald/maxminddb-golang v1.12.0 +## explicit; go 1.19 github.com/oschwald/maxminddb-golang # github.com/patrickmn/go-cache v2.1.0+incompatible ## explicit @@ -43,31 +43,36 @@ github.com/pkg/browser # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# github.com/posener/script v1.1.5 -## explicit; go 1.13 +# github.com/posener/script v1.2.0 +## explicit; go 1.20 github.com/posener/script # github.com/spf13/pflag v1.0.5 ## explicit; go 1.12 github.com/spf13/pflag -# github.com/stretchr/testify v1.8.0 -## explicit; go 1.13 +# github.com/stretchr/testify v1.8.4 +## explicit; go 1.20 github.com/stretchr/testify/assert # go.etcd.io/bbolt v1.3.6 ## explicit; go 1.12 go.etcd.io/bbolt # go4.org/intern v0.0.0-20220617035311-6925f38cc365 ## explicit; go 1.13 -go4.org/intern +# go4.org/netipx v0.0.0-20231129151722-fdeea329fbba +## explicit; go 1.18 +go4.org/netipx # go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 ## explicit; go 1.11 -go4.org/unsafe/assume-no-moving-gc +# golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 +## explicit; go 1.20 +golang.org/x/exp/constraints +golang.org/x/exp/slices # golang.org/x/net v0.18.0 ## explicit; go 1.18 golang.org/x/net/idna # golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 ## explicit golang.org/x/sync/errgroup -# golang.org/x/sys v0.14.0 +# golang.org/x/sys v0.15.0 ## explicit; go 1.18 golang.org/x/sys/plan9 golang.org/x/sys/unix @@ -86,4 +91,3 @@ golang.org/x/text/unicode/norm gopkg.in/yaml.v3 # inet.af/netaddr v0.0.0-20220811202034-502d2d690317 ## explicit; go 1.12 -inet.af/netaddr