mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-23 22:29:59 -05:00
committed by
Ralf Haferkamp
parent
90e4127227
commit
e85d8effc1
14
go.mod
14
go.mod
@@ -64,7 +64,7 @@ require (
|
||||
github.com/open-policy-agent/opa v1.10.1
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||
github.com/opencloud-eu/reva/v2 v2.39.3-0.20251113164418-9fd6b6864c10
|
||||
github.com/opencloud-eu/reva/v2 v2.39.3-0.20251120114614-1b573c55f789
|
||||
github.com/opensearch-project/opensearch-go/v4 v4.5.0
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
@@ -101,14 +101,14 @@ require (
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
|
||||
go.opentelemetry.io/otel/sdk v1.38.0
|
||||
go.opentelemetry.io/otel/trace v1.38.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
golang.org/x/crypto v0.44.0
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/image v0.32.0
|
||||
golang.org/x/net v0.46.0
|
||||
golang.org/x/oauth2 v0.33.0
|
||||
golang.org/x/sync v0.18.0
|
||||
golang.org/x/term v0.37.0
|
||||
golang.org/x/text v0.30.0
|
||||
golang.org/x/text v0.31.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4
|
||||
google.golang.org/grpc v1.76.0
|
||||
google.golang.org/protobuf v1.36.10
|
||||
@@ -242,7 +242,7 @@ require (
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-tpm v0.9.6 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/renameio/v2 v2.0.0 // indirect
|
||||
github.com/google/renameio/v2 v2.0.1 // indirect
|
||||
github.com/gookit/goutil v0.7.1 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
@@ -334,6 +334,9 @@ require (
|
||||
github.com/russellhaering/goxmldsig v1.5.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
||||
github.com/samber/lo v1.51.0 // indirect
|
||||
github.com/samber/slog-common v0.19.0 // indirect
|
||||
github.com/samber/slog-zerolog/v2 v2.9.0 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/segmentio/kafka-go v0.4.49 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||
@@ -403,3 +406,6 @@ replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.202411151126
|
||||
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
|
||||
replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a
|
||||
|
||||
// to get the logger injection (https://github.com/pablodz/inotifywaitgo/pull/11)
|
||||
replace github.com/pablodz/inotifywaitgo v0.0.9 => github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9
|
||||
|
||||
26
go.sum
26
go.sum
@@ -587,8 +587,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/google/renameio/v2 v2.0.1 h1:HyOM6qd9gF9sf15AvhbptGHUnaLTpEI9akAFFU3VyW0=
|
||||
github.com/google/renameio/v2 v2.0.1/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -957,10 +957,12 @@ github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-202505121527
|
||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+lP5lUUIzjRGDg93WrQfZJZCaV1ZP3KeyXi8bzY=
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
|
||||
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIftlX03Bzfbujhp9B54FbgER0VBDWJi/w8RBxJlzxU=
|
||||
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.39.3-0.20251113164418-9fd6b6864c10 h1:9b5O3lzYHmR+aDNo81UYMcDGfUARrHw5Suk4YmqNgJA=
|
||||
github.com/opencloud-eu/reva/v2 v2.39.3-0.20251113164418-9fd6b6864c10/go.mod h1:YxP7b+8olAhgbQBUUnsRQokgf1RkwpEBLq614XXXXHA=
|
||||
github.com/opencloud-eu/reva/v2 v2.39.3-0.20251120114614-1b573c55f789 h1:2B/xhc0Q0W61embhafcBQyY3z5oJ7VS+OjHerd2Jcvg=
|
||||
github.com/opencloud-eu/reva/v2 v2.39.3-0.20251120114614-1b573c55f789/go.mod h1:hJ+wEfhpmKix5/BQpwQPqgK/o9dugaumDFkRG/U6X8E=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
@@ -977,8 +979,6 @@ github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CF
|
||||
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pablodz/inotifywaitgo v0.0.9 h1:njquRbBU7fuwIe5rEvtaniVBjwWzcpdUVptSgzFqZsw=
|
||||
github.com/pablodz/inotifywaitgo v0.0.9/go.mod h1:hAfx2oN+WKg8miwUKPs52trySpPignlRBRxWcXVHku0=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
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=
|
||||
@@ -1091,6 +1091,12 @@ github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
|
||||
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
|
||||
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||
github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI=
|
||||
github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M=
|
||||
github.com/samber/slog-zerolog/v2 v2.9.0 h1:6LkOabJmZdNLaUWkTC3IVVA+dq7b/V0FM6lz6/7+THI=
|
||||
github.com/samber/slog-zerolog/v2 v2.9.0/go.mod h1:gnQW9VnCfM34v2pRMUIGMsZOVbYLqY/v0Wxu6atSVGc=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
@@ -1351,8 +1357,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1591,8 +1597,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
23
vendor/github.com/google/renameio/v2/.golangci.yml
generated
vendored
23
vendor/github.com/google/renameio/v2/.golangci.yml
generated
vendored
@@ -1,5 +1,24 @@
|
||||
version: "2"
|
||||
linters:
|
||||
disable:
|
||||
- errcheck
|
||||
- errcheck
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- gofmt
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
4
vendor/github.com/google/renameio/v2/README.md
generated
vendored
4
vendor/github.com/google/renameio/v2/README.md
generated
vendored
@@ -1,6 +1,6 @@
|
||||
[](https://github.com/google/renameio/actions?query=workflow%3ATest)
|
||||
[](https://pkg.go.dev/github.com/google/renameio)
|
||||
[](https://goreportcard.com/report/github.com/google/renameio)
|
||||
[](https://pkg.go.dev/github.com/google/renameio/v2)
|
||||
[](https://goreportcard.com/report/github.com/google/renameio/v2)
|
||||
|
||||
The `renameio` Go package provides a way to atomically create or replace a file or
|
||||
symbolic link.
|
||||
|
||||
9
vendor/github.com/google/renameio/v2/option.go
generated
vendored
9
vendor/github.com/google/renameio/v2/option.go
generated
vendored
@@ -77,3 +77,12 @@ func WithExistingPermissions() Option {
|
||||
c.attemptPermCopy = true
|
||||
})
|
||||
}
|
||||
|
||||
// WithReplaceOnClose causes PendingFile.Close() to actually call
|
||||
// CloseAtomicallyReplace(). This means PendingFile implements io.Closer while
|
||||
// maintaining atomicity per default.
|
||||
func WithReplaceOnClose() Option {
|
||||
return optionFunc(func(c *config) {
|
||||
c.renameOnClose = true
|
||||
})
|
||||
}
|
||||
|
||||
23
vendor/github.com/google/renameio/v2/tempfile.go
generated
vendored
23
vendor/github.com/google/renameio/v2/tempfile.go
generated
vendored
@@ -114,9 +114,10 @@ func tempDir(dir, dest string) string {
|
||||
type PendingFile struct {
|
||||
*os.File
|
||||
|
||||
path string
|
||||
done bool
|
||||
closed bool
|
||||
path string
|
||||
done bool
|
||||
closed bool
|
||||
replaceOnClose bool
|
||||
}
|
||||
|
||||
// Cleanup is a no-op if CloseAtomicallyReplace succeeded, and otherwise closes
|
||||
@@ -131,7 +132,7 @@ func (t *PendingFile) Cleanup() error {
|
||||
// reporting, there is nothing the caller can recover here.
|
||||
var closeErr error
|
||||
if !t.closed {
|
||||
closeErr = t.Close()
|
||||
closeErr = t.File.Close()
|
||||
}
|
||||
if err := os.Remove(t.Name()); err != nil {
|
||||
return err
|
||||
@@ -159,7 +160,7 @@ func (t *PendingFile) CloseAtomicallyReplace() error {
|
||||
return err
|
||||
}
|
||||
t.closed = true
|
||||
if err := t.Close(); err != nil {
|
||||
if err := t.File.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(t.Name(), t.path); err != nil {
|
||||
@@ -169,6 +170,15 @@ func (t *PendingFile) CloseAtomicallyReplace() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the file. By default it just calls Close() on the underlying file. For PendingFiles created with
|
||||
// WithReplaceOnClose it calls CloseAtomicallyReplace() instead.
|
||||
func (t *PendingFile) Close() error {
|
||||
if t.replaceOnClose {
|
||||
return t.CloseAtomicallyReplace()
|
||||
}
|
||||
return t.File.Close()
|
||||
}
|
||||
|
||||
// TempFile creates a temporary file destined to atomically creating or
|
||||
// replacing the destination file at path.
|
||||
//
|
||||
@@ -189,6 +199,7 @@ type config struct {
|
||||
attemptPermCopy bool
|
||||
ignoreUmask bool
|
||||
chmod *os.FileMode
|
||||
renameOnClose bool
|
||||
}
|
||||
|
||||
// NewPendingFile creates a temporary file destined to atomically creating or
|
||||
@@ -244,7 +255,7 @@ func NewPendingFile(path string, opts ...Option) (*PendingFile, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return &PendingFile{File: f, path: cfg.path}, nil
|
||||
return &PendingFile{File: f, path: cfg.path, replaceOnClose: cfg.renameOnClose}, nil
|
||||
}
|
||||
|
||||
// Symlink wraps os.Symlink, replacing an existing symlink with the same name
|
||||
|
||||
6
vendor/github.com/opencloud-eu/reva/v2/internal/grpc/interceptors/appctx/appctx.go
generated
vendored
6
vendor/github.com/opencloud-eu/reva/v2/internal/grpc/interceptors/appctx/appctx.go
generated
vendored
@@ -24,7 +24,7 @@ import (
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/appctx"
|
||||
"github.com/rs/zerolog"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
@@ -42,7 +42,7 @@ func NewUnary(log zerolog.Logger, tp trace.TracerProvider) grpc.UnaryServerInter
|
||||
}
|
||||
_, file, _, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
span.SetAttributes(semconv.CodeFilepathKey.String(file))
|
||||
span.SetAttributes(semconv.CodeFilePathKey.String(file))
|
||||
}
|
||||
|
||||
sub := log.With().Str("traceid", span.SpanContext().TraceID().String()).Logger()
|
||||
@@ -67,7 +67,7 @@ func NewStream(log zerolog.Logger, tp trace.TracerProvider) grpc.StreamServerInt
|
||||
}
|
||||
_, file, _, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
span.SetAttributes(semconv.CodeFilepathKey.String(file))
|
||||
span.SetAttributes(semconv.CodeFilePathKey.String(file))
|
||||
}
|
||||
|
||||
sub := log.With().Str("traceid", span.SpanContext().TraceID().String()).Logger()
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/internal/grpc/interceptors/auth/auth.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/internal/grpc/interceptors/auth/auth.go
generated
vendored
@@ -38,7 +38,7 @@ import (
|
||||
tokenmgr "github.com/opencloud-eu/reva/v2/pkg/token/manager/registry"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/internal/http/interceptors/auth/auth.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/internal/http/interceptors/auth/auth.go
generated
vendored
@@ -49,7 +49,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/otel"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
@@ -127,8 +127,8 @@ func (s *svc) setHandler() {
|
||||
ctx, span := tracer.Start(ctx, "HandlerFunc")
|
||||
defer span.End()
|
||||
span.SetAttributes(
|
||||
semconv.HTTPMethodKey.String(r.Method),
|
||||
semconv.HTTPURLKey.String(r.URL.String()),
|
||||
semconv.HTTPRequestMethodKey.String(r.Method),
|
||||
semconv.URLFullKey.String(r.URL.String()),
|
||||
)
|
||||
r = r.WithContext(ctx)
|
||||
s.doRequest(w, r)
|
||||
|
||||
@@ -58,7 +58,7 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
)
|
||||
@@ -243,7 +243,7 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "Invalid Depth header value")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", dh).Msg(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
|
||||
@@ -255,7 +255,7 @@ func (p *Handler) HandlePathPropfind(w http.ResponseWriter, r *http.Request, ns
|
||||
if depth == net.DepthInfinity && !p.c.AllowPropfindDepthInfinitiy {
|
||||
span.RecordError(errors.ErrInvalidDepth)
|
||||
span.SetStatus(codes.Error, "DEPTH: infinity is not supported")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
|
||||
@@ -312,7 +312,7 @@ func (p *Handler) HandleSpacesPropfind(w http.ResponseWriter, r *http.Request, s
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "Invalid Depth header value")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", dh).Msg(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
|
||||
@@ -324,7 +324,7 @@ func (p *Handler) HandleSpacesPropfind(w http.ResponseWriter, r *http.Request, s
|
||||
if depth == net.DepthInfinity && !p.c.AllowPropfindDepthInfinitiy {
|
||||
span.RecordError(errors.ErrInvalidDepth)
|
||||
span.SetStatus(codes.Error, "DEPTH: infinity is not supported")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", dh).Msg(errors.ErrInvalidDepth.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
|
||||
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/appctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rhttp/router"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
)
|
||||
|
||||
// PublicFileHandler handles requests on a shared file. it needs to be wrapped in a collection
|
||||
@@ -100,7 +100,7 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s
|
||||
if !ok {
|
||||
span.RecordError(ocdaverrors.ErrTokenStatInfoMissing)
|
||||
span.SetStatus(codes.Error, ocdaverrors.ErrTokenStatInfoMissing.Error())
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusInternalServerError))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusInternalServerError))
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
b, err := ocdaverrors.Marshal(http.StatusInternalServerError, ocdaverrors.ErrTokenStatInfoMissing.Error(), "", "")
|
||||
ocdaverrors.HandleWebdavError(appctx.GetLogger(ctx), w, b, err)
|
||||
@@ -114,7 +114,7 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "Invalid Depth header value")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", dh).Msg(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
|
||||
@@ -126,7 +126,7 @@ func (s *svc) handlePropfindOnToken(w http.ResponseWriter, r *http.Request, ns s
|
||||
if depth == net.DepthInfinity && !s.c.AllowPropfindDepthInfinitiy {
|
||||
span.RecordError(ocdaverrors.ErrInvalidDepth)
|
||||
span.SetStatus(codes.Error, "DEPTH: infinity is not supported")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", dh).Msg(ocdaverrors.ErrInvalidDepth.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", dh)
|
||||
|
||||
@@ -41,7 +41,7 @@ import (
|
||||
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.20.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/appctx"
|
||||
ctxpkg "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
@@ -200,7 +200,7 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, "Invalid Depth header value")
|
||||
span.SetAttributes(semconv.HTTPStatusCodeKey.Int(http.StatusBadRequest))
|
||||
span.SetAttributes(semconv.HTTPResponseStatusCodeKey.Int(http.StatusBadRequest))
|
||||
sublog.Debug().Str("depth", r.Header.Get(net.HeaderDepth)).Msg(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
m := fmt.Sprintf("Invalid Depth header value: %v", r.Header.Get(net.HeaderDepth))
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/cache/stat.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/cache/stat.go
generated
vendored
@@ -28,7 +28,7 @@ import (
|
||||
"go-micro.dev/v4/store"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore/blobstore.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore/blobstore.go
generated
vendored
@@ -67,7 +67,7 @@ func (bs *Blobstore) Upload(n *node.Node, source, copyTarget string) error {
|
||||
_ = sourceFile.Close()
|
||||
}()
|
||||
|
||||
tempFile, err := os.OpenFile(tempName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0700)
|
||||
tempFile, err := os.OpenFile(tempName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create temp file '%s': %v", tempName, err)
|
||||
}
|
||||
|
||||
7
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go
generated
vendored
7
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go
generated
vendored
@@ -22,6 +22,7 @@ package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -31,6 +32,7 @@ import (
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
|
||||
"github.com/pablodz/inotifywaitgo/inotifywaitgo"
|
||||
"github.com/rs/zerolog"
|
||||
slogzerolog "github.com/samber/slog-zerolog/v2"
|
||||
)
|
||||
|
||||
type InotifyWatcher struct {
|
||||
@@ -56,6 +58,10 @@ func (iw *InotifyWatcher) Watch(path string) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// create a slog logger to be passed to the settings of inotifywatcher to log into
|
||||
logger := slog.New(slogzerolog.Option{Level: slog.LevelDebug, Logger: iw.log}.NewZerologHandler())
|
||||
|
||||
events := make(chan inotifywaitgo.FileEvent)
|
||||
errors := make(chan error)
|
||||
|
||||
@@ -76,6 +82,7 @@ func (iw *InotifyWatcher) Watch(path string) {
|
||||
Monitor: true,
|
||||
},
|
||||
Verbose: false,
|
||||
Log: logger,
|
||||
})
|
||||
|
||||
for {
|
||||
|
||||
8
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/revisions.go
generated
vendored
8
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/revisions.go
generated
vendored
@@ -272,7 +272,7 @@ func (tp *Tree) DownloadRevision(ctx context.Context, ref *provider.Reference, r
|
||||
return ri, reader, nil
|
||||
}
|
||||
|
||||
func (tp *Tree) RestoreRevision(ctx context.Context, srcNode, targetNode metadata.MetadataNode) error {
|
||||
func (tp *Tree) RestoreRevision(ctx context.Context, srcNode, targetNode metadata.MetadataNode, mtime time.Time) error {
|
||||
source := srcNode.InternalPath()
|
||||
target := targetNode.InternalPath()
|
||||
rf, err := os.Open(source)
|
||||
@@ -305,8 +305,10 @@ func (tp *Tree) RestoreRevision(ctx context.Context, srcNode, targetNode metadat
|
||||
return errtypes.InternalError("failed to copy blob xattrs to old revision to node: " + err.Error())
|
||||
}
|
||||
|
||||
// always set the node mtime to the current time
|
||||
mtime := time.Now()
|
||||
// set the node mtime to the current time if no mtime was provided
|
||||
if mtime.IsZero() {
|
||||
mtime = time.Now()
|
||||
}
|
||||
err = os.Chtimes(target, mtime, mtime)
|
||||
if err != nil {
|
||||
return errtypes.InternalError("failed to update times:" + err.Error())
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/cache"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/filelocks"
|
||||
)
|
||||
|
||||
var _metadataOffloadedAttr = prefixes.OcPrefix + "metadata_offloaded"
|
||||
@@ -121,12 +120,11 @@ func (b HybridBackend) list(ctx context.Context, n MetadataNode, acquireLock boo
|
||||
|
||||
// listing xattrs failed, try again, either with lock or without
|
||||
if acquireLock {
|
||||
f, err := lockedfile.OpenFile(filePath+filelocks.LockFileSuffix, os.O_CREATE|os.O_WRONLY, 0600)
|
||||
unlock, err := b.Lock(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Warning: do not remove the lockfile or we may lock the same file more than once, https://github.com/opencloud-eu/opencloud/issues/1793
|
||||
defer f.Close()
|
||||
defer func() { _ = unlock() }()
|
||||
|
||||
}
|
||||
return xattr.List(filePath)
|
||||
@@ -375,12 +373,11 @@ func (b HybridBackend) offloadMetadata(ctx context.Context, n MetadataNode) erro
|
||||
func (b HybridBackend) Remove(ctx context.Context, n MetadataNode, key string, acquireLock bool) error {
|
||||
path := n.InternalPath()
|
||||
if acquireLock {
|
||||
lockedFile, err := lockedfile.OpenFile(path+filelocks.LockFileSuffix, os.O_CREATE|os.O_WRONLY, 0600)
|
||||
unlock, err := b.Lock(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Warning: do not remove the lockfile or we may lock the same file more than once, https://github.com/opencloud-eu/opencloud/issues/1793
|
||||
defer lockedFile.Close()
|
||||
defer func() { _ = unlock() }()
|
||||
}
|
||||
|
||||
if isOffloadingAttribute(key) {
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node/node.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node/node.go
generated
vendored
@@ -129,7 +129,7 @@ type Tree interface {
|
||||
Delete(ctx context.Context, node *Node) (err error)
|
||||
|
||||
InitNewNode(ctx context.Context, n *Node, fsize uint64) (metadata.UnlockFunc, error)
|
||||
RestoreRevision(ctx context.Context, source, target metadata.MetadataNode) (err error)
|
||||
RestoreRevision(ctx context.Context, source, target metadata.MetadataNode, mtime time.Time) (err error)
|
||||
|
||||
WriteBlob(node *Node, source string) error
|
||||
ReadBlob(node *Node) (io.ReadCloser, error)
|
||||
|
||||
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/revisions.go
generated
vendored
2
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/revisions.go
generated
vendored
@@ -131,7 +131,7 @@ func (fs *Decomposedfs) RestoreRevision(ctx context.Context, ref *provider.Refer
|
||||
|
||||
// restore revision
|
||||
restoredRevisionPath := fs.lu.InternalPath(spaceID, revisionKey)
|
||||
if err := fs.tp.RestoreRevision(ctx, revisionNode, n); err != nil {
|
||||
if err := fs.tp.RestoreRevision(ctx, revisionNode, n, time.Now()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ func (tp *Tree) getRevisionNode(ctx context.Context, ref *provider.Reference, re
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (tp *Tree) RestoreRevision(ctx context.Context, sourceNode, targetNode metadata.MetadataNode) error {
|
||||
func (tp *Tree) RestoreRevision(ctx context.Context, sourceNode, targetNode metadata.MetadataNode, mtime time.Time) error {
|
||||
err := tp.lookup.CopyMetadata(ctx, sourceNode, targetNode, func(attributeName string, value []byte) (newValue []byte, copy bool) {
|
||||
return value, strings.HasPrefix(attributeName, prefixes.ChecksumPrefix) ||
|
||||
attributeName == prefixes.TypeAttr ||
|
||||
@@ -340,10 +340,13 @@ func (tp *Tree) RestoreRevision(ctx context.Context, sourceNode, targetNode meta
|
||||
if err != nil {
|
||||
return errtypes.InternalError("failed to copy blob xattrs to old revision to node: " + err.Error())
|
||||
}
|
||||
// always set the node mtime to the current time
|
||||
// set the node mtime to the current time if no mtime was provided
|
||||
if mtime.IsZero() {
|
||||
mtime = time.Now()
|
||||
}
|
||||
err = tp.lookup.MetadataBackend().SetMultiple(ctx, targetNode,
|
||||
map[string][]byte{
|
||||
prefixes.MTimeAttr: []byte(time.Now().UTC().Format(time.RFC3339Nano)),
|
||||
prefixes.MTimeAttr: []byte(mtime.UTC().Format(time.RFC3339Nano)),
|
||||
},
|
||||
false)
|
||||
if err != nil {
|
||||
|
||||
66
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go
generated
vendored
66
vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go
generated
vendored
@@ -292,7 +292,10 @@ func (session *DecomposedFsSession) Finalize(ctx context.Context) (err error) {
|
||||
revisionNode := node.New(session.SpaceID(), session.NodeID(), "", "", session.Size(), session.ID(),
|
||||
provider.ResourceType_RESOURCE_TYPE_FILE, session.SpaceOwner(), session.store.lu)
|
||||
|
||||
switch spaceRoot, err := session.store.lu.NodeFromSpaceID(ctx, session.SpaceID()); {
|
||||
var (
|
||||
spaceRoot *node.Node
|
||||
)
|
||||
switch spaceRoot, err = session.store.lu.NodeFromSpaceID(ctx, session.SpaceID()); {
|
||||
case err != nil:
|
||||
return fmt.Errorf("failed to get space root for space id %s: %v", session.SpaceID(), err)
|
||||
case spaceRoot == nil:
|
||||
@@ -310,6 +313,31 @@ func (session *DecomposedFsSession) Finalize(ctx context.Context) (err error) {
|
||||
}
|
||||
defer func() { _ = unlock() }()
|
||||
|
||||
isProcessing := revisionNode.IsProcessing(ctx)
|
||||
var procssingID string
|
||||
if isProcessing {
|
||||
procssingID, _ = revisionNode.ProcessingID(ctx)
|
||||
}
|
||||
|
||||
// another upload on this node is in progress or has finished since we started
|
||||
if !isProcessing || procssingID != session.ID() {
|
||||
versionID := revisionNode.ID + node.RevisionIDDelimiter + session.MTime().UTC().Format(time.RFC3339Nano)
|
||||
revisionNode, err = node.ReadNode(ctx, session.store.lu, session.SpaceID(), versionID, false, spaceRoot, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read revision node %s for upload finalization: %w", versionID, err)
|
||||
}
|
||||
if !revisionNode.Exists {
|
||||
return fmt.Errorf("revision node %s for upload finalization does not exist", versionID)
|
||||
}
|
||||
// lock this node as well, before writing the blob
|
||||
revisionNodeUnlock, err := session.store.lu.MetadataBackend().Lock(revisionNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appctx.GetLogger(ctx).Debug().Str("new nodepath", revisionNode.InternalPath()).Msg("uploading to revision node, that was created for us by another upload")
|
||||
defer func() { _ = revisionNodeUnlock() }()
|
||||
}
|
||||
|
||||
// upload the data to the blobstore
|
||||
_, subspan := tracer.Start(ctx, "WriteBlob")
|
||||
err = session.store.tp.WriteBlob(revisionNode, session.binPath())
|
||||
@@ -343,35 +371,45 @@ func (session *DecomposedFsSession) removeNode(ctx context.Context) {
|
||||
// cleanup cleans up after the upload is finished
|
||||
func (session *DecomposedFsSession) Cleanup(revertNodeMetadata, cleanBin, cleanInfo bool) {
|
||||
ctx := session.Context(context.Background())
|
||||
sublog := session.store.log.With().Str("cleanup sessionid", session.ID()).Bool("revertNodeMetadata", revertNodeMetadata).Bool("cleanBin", cleanBin).
|
||||
Bool("cleanInfo", cleanInfo).Logger()
|
||||
|
||||
if revertNodeMetadata {
|
||||
n, err := session.Node(ctx)
|
||||
if err != nil {
|
||||
appctx.GetLogger(ctx).Error().Err(err).Str("sessionid", session.ID()).Msg("reading node for session failed")
|
||||
sublog.Error().Err(err).Msg("reading node for session failed")
|
||||
} else {
|
||||
if session.NodeExists() && session.info.MetaData["versionID"] != "" {
|
||||
versionID := session.info.MetaData["versionID"]
|
||||
revisionNode := node.NewBaseNode(n.SpaceID, versionID, session.store.lu)
|
||||
sublog.Debug().Str("nodepath", n.InternalPath()).Str("versionID", versionID).Msg("restoring revision")
|
||||
revisionNode, err := node.ReadNode(ctx, session.store.lu, session.SpaceID(), versionID, false, n.SpaceRoot, false)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("versionID", versionID).Msg("reading revision node failed")
|
||||
}
|
||||
|
||||
if err := session.store.lu.CopyMetadata(ctx, revisionNode, n, func(attributeName string, value []byte) (newValue []byte, copy bool) {
|
||||
return value, strings.HasPrefix(attributeName, prefixes.ChecksumPrefix) ||
|
||||
attributeName == prefixes.TypeAttr ||
|
||||
attributeName == prefixes.BlobIDAttr ||
|
||||
attributeName == prefixes.BlobsizeAttr ||
|
||||
attributeName == prefixes.MTimeAttr
|
||||
}, true); err != nil {
|
||||
appctx.GetLogger(ctx).Info().Str("version", versionID).Str("nodepath", n.InternalPath()).Err(err).Msg("renaming version node failed")
|
||||
if !revisionNode.Exists {
|
||||
sublog.Error().Str("versionID", versionID).Msg("revision node does not exist")
|
||||
}
|
||||
|
||||
// restore the revision
|
||||
mtime, err := revisionNode.GetMTime(ctx)
|
||||
if err != nil {
|
||||
sublog.Error().Err(err).Str("versionID", versionID).Msg("getting mtime of revision node failed")
|
||||
mtime = time.Now()
|
||||
}
|
||||
|
||||
if err := session.store.tp.RestoreRevision(ctx, revisionNode, n, mtime); err != nil {
|
||||
sublog.Error().Err(err).Str("versionID", versionID).Msg("restoring revision node failed")
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(revisionNode.InternalPath()); err != nil {
|
||||
appctx.GetLogger(ctx).Info().Str("version", versionID).Str("nodepath", n.InternalPath()).Err(err).Msg("error removing version")
|
||||
sublog.Error().Err(err).Str("revisionpath", revisionNode.InternalPath()).Msg("removing restored revision file failed")
|
||||
}
|
||||
|
||||
} else {
|
||||
// if no other upload session is in progress (processing id != session id) or has finished (processing id == "")
|
||||
latestSession, err := n.ProcessingID(ctx)
|
||||
if err != nil {
|
||||
appctx.GetLogger(ctx).Error().Err(err).Str("spaceid", n.SpaceID).Str("nodeid", n.ID).Str("uploadid", session.ID()).Msg("reading processingid for session failed")
|
||||
sublog.Error().Err(err).Str("spaceid", n.SpaceID).Str("nodeid", n.ID).Str("uploadid", session.ID()).Msg("reading processingid for session failed")
|
||||
}
|
||||
if latestSession == session.ID() {
|
||||
// actually delete the node
|
||||
|
||||
4
vendor/github.com/pablodz/inotifywaitgo/inotifywaitgo/models.go
generated
vendored
4
vendor/github.com/pablodz/inotifywaitgo/inotifywaitgo/models.go
generated
vendored
@@ -1,5 +1,7 @@
|
||||
package inotifywaitgo
|
||||
|
||||
import "log/slog"
|
||||
|
||||
type Settings struct {
|
||||
// Directory to watch
|
||||
Dir string
|
||||
@@ -13,6 +15,8 @@ type Settings struct {
|
||||
KillOthers bool
|
||||
// verbose
|
||||
Verbose bool
|
||||
// Logger
|
||||
Log *slog.Logger
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
|
||||
18
vendor/github.com/pablodz/inotifywaitgo/inotifywaitgo/watcher.go
generated
vendored
18
vendor/github.com/pablodz/inotifywaitgo/inotifywaitgo/watcher.go
generated
vendored
@@ -3,8 +3,9 @@ package inotifywaitgo
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
@@ -14,13 +15,13 @@ import (
|
||||
func WatchPath(s *Settings) {
|
||||
// Check if inotifywait is installed
|
||||
if ok, err := checkDependencies(); !ok || err != nil {
|
||||
s.ErrorChan <- fmt.Errorf(NOT_INSTALLED)
|
||||
s.ErrorChan <- errors.New(NOT_INSTALLED)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the directory exists
|
||||
if _, err := os.Stat(s.Dir); os.IsNotExist(err) {
|
||||
s.ErrorChan <- fmt.Errorf(DIR_NOT_EXISTS)
|
||||
s.ErrorChan <- errors.New(DIR_NOT_EXISTS)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -49,15 +50,20 @@ func WatchPath(s *Settings) {
|
||||
return
|
||||
}
|
||||
|
||||
logger := s.Log
|
||||
if logger == nil {
|
||||
logger = slog.New(slog.NewTextHandler(os.Stdout, nil))
|
||||
}
|
||||
|
||||
// Read the output of inotifywait and split it into lines
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
log.Println(line)
|
||||
logger.Debug(line)
|
||||
|
||||
parts, err := parseLine(line)
|
||||
if err != nil || len(parts) < 2 {
|
||||
s.ErrorChan <- fmt.Errorf(INVALID_OUTPUT)
|
||||
s.ErrorChan <- errors.New(INVALID_OUTPUT)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -66,7 +72,7 @@ func WatchPath(s *Settings) {
|
||||
|
||||
if s.Verbose {
|
||||
for _, eventStr := range eventStrs {
|
||||
log.Printf("eventStr: <%s>, <%s>", eventStr, line)
|
||||
logger.Debug("eventStr: <%s>, <%s>", eventStr, line)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
38
vendor/github.com/samber/lo/.gitignore
generated
vendored
Normal file
38
vendor/github.com/samber/lo/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/go
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=go
|
||||
|
||||
### Go ###
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
### Go Patch ###
|
||||
/vendor/
|
||||
/Godeps/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/go
|
||||
|
||||
cover.out
|
||||
cover.html
|
||||
.vscode
|
||||
|
||||
.idea/
|
||||
8
vendor/github.com/samber/lo/Dockerfile
generated
vendored
Normal file
8
vendor/github.com/samber/lo/Dockerfile
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
FROM golang:1.23.1
|
||||
|
||||
WORKDIR /go/src/github.com/samber/lo
|
||||
|
||||
COPY Makefile go.* ./
|
||||
|
||||
RUN make tools
|
||||
21
vendor/github.com/samber/lo/LICENSE
generated
vendored
Normal file
21
vendor/github.com/samber/lo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2025 Samuel Berthe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
42
vendor/github.com/samber/lo/Makefile
generated
vendored
Normal file
42
vendor/github.com/samber/lo/Makefile
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
build:
|
||||
go build -v ./...
|
||||
|
||||
test:
|
||||
go test -race -v ./...
|
||||
watch-test:
|
||||
reflex -t 50ms -s -- sh -c 'gotest -race -v ./...'
|
||||
|
||||
bench:
|
||||
go test -benchmem -count 3 -bench ./...
|
||||
watch-bench:
|
||||
reflex -t 50ms -s -- sh -c 'go test -benchmem -count 3 -bench ./...'
|
||||
|
||||
coverage:
|
||||
go test -v -coverprofile=cover.out -covermode=atomic ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
# tools
|
||||
tools:
|
||||
go install github.com/cespare/reflex@latest
|
||||
go install github.com/rakyll/gotest@latest
|
||||
go install github.com/psampaz/go-mod-outdated@latest
|
||||
go install github.com/jondot/goweight@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
go get -t -u golang.org/x/tools/cmd/cover
|
||||
go install github.com/sonatype-nexus-community/nancy@latest
|
||||
go mod tidy
|
||||
|
||||
lint:
|
||||
golangci-lint run --timeout 60s --max-same-issues 50 ./...
|
||||
lint-fix:
|
||||
golangci-lint run --timeout 60s --max-same-issues 50 --fix ./...
|
||||
|
||||
audit: tools
|
||||
go list -json -m all | nancy sleuth
|
||||
|
||||
outdated: tools
|
||||
go list -u -m -json all | go-mod-outdated -update -direct
|
||||
|
||||
weight: tools
|
||||
goweight
|
||||
4213
vendor/github.com/samber/lo/README.md
generated
vendored
Normal file
4213
vendor/github.com/samber/lo/README.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
314
vendor/github.com/samber/lo/channel.go
generated
vendored
Normal file
314
vendor/github.com/samber/lo/channel.go
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo/internal/rand"
|
||||
)
|
||||
|
||||
type DispatchingStrategy[T any] func(msg T, index uint64, channels []<-chan T) int
|
||||
|
||||
// ChannelDispatcher distributes messages from input channels into N child channels.
|
||||
// Close events are propagated to children.
|
||||
// Underlying channels can have a fixed buffer capacity or be unbuffered when cap is 0.
|
||||
func ChannelDispatcher[T any](stream <-chan T, count int, channelBufferCap int, strategy DispatchingStrategy[T]) []<-chan T {
|
||||
children := createChannels[T](count, channelBufferCap)
|
||||
|
||||
roChildren := channelsToReadOnly(children)
|
||||
|
||||
go func() {
|
||||
// propagate channel closing to children
|
||||
defer closeChannels(children)
|
||||
|
||||
var i uint64 = 0
|
||||
|
||||
for {
|
||||
msg, ok := <-stream
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
destination := strategy(msg, i, roChildren) % count
|
||||
children[destination] <- msg
|
||||
|
||||
i++
|
||||
}
|
||||
}()
|
||||
|
||||
return roChildren
|
||||
}
|
||||
|
||||
func createChannels[T any](count int, channelBufferCap int) []chan T {
|
||||
children := make([]chan T, 0, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
children = append(children, make(chan T, channelBufferCap))
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
func channelsToReadOnly[T any](children []chan T) []<-chan T {
|
||||
roChildren := make([]<-chan T, 0, len(children))
|
||||
|
||||
for i := range children {
|
||||
roChildren = append(roChildren, children[i])
|
||||
}
|
||||
|
||||
return roChildren
|
||||
}
|
||||
|
||||
func closeChannels[T any](children []chan T) {
|
||||
for i := 0; i < len(children); i++ {
|
||||
close(children[i])
|
||||
}
|
||||
}
|
||||
|
||||
func channelIsNotFull[T any](ch <-chan T) bool {
|
||||
return cap(ch) == 0 || len(ch) < cap(ch)
|
||||
}
|
||||
|
||||
// DispatchingStrategyRoundRobin distributes messages in a rotating sequential manner.
|
||||
// If the channel capacity is exceeded, the next channel will be selected and so on.
|
||||
func DispatchingStrategyRoundRobin[T any](msg T, index uint64, channels []<-chan T) int {
|
||||
for {
|
||||
i := int(index % uint64(len(channels)))
|
||||
if channelIsNotFull(channels[i]) {
|
||||
return i
|
||||
}
|
||||
|
||||
index++
|
||||
time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥
|
||||
}
|
||||
}
|
||||
|
||||
// DispatchingStrategyRandom distributes messages in a random manner.
|
||||
// If the channel capacity is exceeded, another random channel will be selected and so on.
|
||||
func DispatchingStrategyRandom[T any](msg T, index uint64, channels []<-chan T) int {
|
||||
for {
|
||||
i := rand.IntN(len(channels))
|
||||
if channelIsNotFull(channels[i]) {
|
||||
return i
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥
|
||||
}
|
||||
}
|
||||
|
||||
// DispatchingStrategyWeightedRandom distributes messages in a weighted manner.
|
||||
// If the channel capacity is exceeded, another random channel will be selected and so on.
|
||||
func DispatchingStrategyWeightedRandom[T any](weights []int) DispatchingStrategy[T] {
|
||||
seq := []int{}
|
||||
|
||||
for i := 0; i < len(weights); i++ {
|
||||
for j := 0; j < weights[i]; j++ {
|
||||
seq = append(seq, i)
|
||||
}
|
||||
}
|
||||
|
||||
return func(msg T, index uint64, channels []<-chan T) int {
|
||||
for {
|
||||
i := seq[rand.IntN(len(seq))]
|
||||
if channelIsNotFull(channels[i]) {
|
||||
return i
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DispatchingStrategyFirst distributes messages in the first non-full channel.
|
||||
// If the capacity of the first channel is exceeded, the second channel will be selected and so on.
|
||||
func DispatchingStrategyFirst[T any](msg T, index uint64, channels []<-chan T) int {
|
||||
for {
|
||||
for i := range channels {
|
||||
if channelIsNotFull(channels[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥
|
||||
}
|
||||
}
|
||||
|
||||
// DispatchingStrategyLeast distributes messages in the emptiest channel.
|
||||
func DispatchingStrategyLeast[T any](msg T, index uint64, channels []<-chan T) int {
|
||||
seq := Range(len(channels))
|
||||
|
||||
return MinBy(seq, func(item int, min int) bool {
|
||||
return len(channels[item]) < len(channels[min])
|
||||
})
|
||||
}
|
||||
|
||||
// DispatchingStrategyMost distributes messages in the fullest channel.
|
||||
// If the channel capacity is exceeded, the next channel will be selected and so on.
|
||||
func DispatchingStrategyMost[T any](msg T, index uint64, channels []<-chan T) int {
|
||||
seq := Range(len(channels))
|
||||
|
||||
return MaxBy(seq, func(item int, max int) bool {
|
||||
return len(channels[item]) > len(channels[max]) && channelIsNotFull(channels[item])
|
||||
})
|
||||
}
|
||||
|
||||
// SliceToChannel returns a read-only channels of collection elements.
|
||||
func SliceToChannel[T any](bufferSize int, collection []T) <-chan T {
|
||||
ch := make(chan T, bufferSize)
|
||||
|
||||
go func() {
|
||||
for i := range collection {
|
||||
ch <- collection[i]
|
||||
}
|
||||
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// ChannelToSlice returns a slice built from channels items. Blocks until channel closes.
|
||||
func ChannelToSlice[T any](ch <-chan T) []T {
|
||||
collection := []T{}
|
||||
|
||||
for item := range ch {
|
||||
collection = append(collection, item)
|
||||
}
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
// Generator implements the generator design pattern.
|
||||
func Generator[T any](bufferSize int, generator func(yield func(T))) <-chan T {
|
||||
ch := make(chan T, bufferSize)
|
||||
|
||||
go func() {
|
||||
// WARNING: infinite loop
|
||||
generator(func(t T) {
|
||||
ch <- t
|
||||
})
|
||||
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// Buffer creates a slice of n elements from a channel. Returns the slice and the slice length.
|
||||
// @TODO: we should probably provide an helper that reuse the same buffer.
|
||||
func Buffer[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
|
||||
buffer := make([]T, 0, size)
|
||||
index := 0
|
||||
now := time.Now()
|
||||
|
||||
for ; index < size; index++ {
|
||||
item, ok := <-ch
|
||||
if !ok {
|
||||
return buffer, index, time.Since(now), false
|
||||
}
|
||||
|
||||
buffer = append(buffer, item)
|
||||
}
|
||||
|
||||
return buffer, index, time.Since(now), true
|
||||
}
|
||||
|
||||
// Batch creates a slice of n elements from a channel. Returns the slice and the slice length.
|
||||
//
|
||||
// Deprecated: Use [Buffer] instead.
|
||||
func Batch[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
|
||||
return Buffer(ch, size)
|
||||
}
|
||||
|
||||
// BufferWithContext creates a slice of n elements from a channel, with context. Returns the slice and the slice length.
|
||||
// @TODO: we should probably provide an helper that reuse the same buffer.
|
||||
func BufferWithContext[T any](ctx context.Context, ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
|
||||
buffer := make([]T, 0, size)
|
||||
now := time.Now()
|
||||
|
||||
for index := 0; index < size; index++ {
|
||||
select {
|
||||
case item, ok := <-ch:
|
||||
if !ok {
|
||||
return buffer, index, time.Since(now), false
|
||||
}
|
||||
|
||||
buffer = append(buffer, item)
|
||||
|
||||
case <-ctx.Done():
|
||||
return buffer, index, time.Since(now), true
|
||||
}
|
||||
}
|
||||
|
||||
return buffer, size, time.Since(now), true
|
||||
}
|
||||
|
||||
// BufferWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length.
|
||||
func BufferWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
return BufferWithContext(ctx, ch, size)
|
||||
}
|
||||
|
||||
// BatchWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length.
|
||||
//
|
||||
// Deprecated: Use [BufferWithTimeout] instead.
|
||||
func BatchWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) {
|
||||
return BufferWithTimeout(ch, size, timeout)
|
||||
}
|
||||
|
||||
// FanIn collects messages from multiple input channels into a single buffered channel.
|
||||
// Output messages has no priority. When all upstream channels reach EOF, downstream channel closes.
|
||||
func FanIn[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
|
||||
out := make(chan T, channelBufferCap)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Start an output goroutine for each input channel in upstreams.
|
||||
wg.Add(len(upstreams))
|
||||
for i := range upstreams {
|
||||
go func(index int) {
|
||||
for n := range upstreams[index] {
|
||||
out <- n
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Start a goroutine to close out once all the output goroutines are done.
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
// ChannelMerge collects messages from multiple input channels into a single buffered channel.
|
||||
// Output messages has no priority. When all upstream channels reach EOF, downstream channel closes.
|
||||
//
|
||||
// Deprecated: Use [FanIn] instead.
|
||||
func ChannelMerge[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
|
||||
return FanIn(channelBufferCap, upstreams...)
|
||||
}
|
||||
|
||||
// FanOut broadcasts all the upstream messages to multiple downstream channels.
|
||||
// When upstream channel reach EOF, downstream channels close. If any downstream
|
||||
// channels is full, broadcasting is paused.
|
||||
func FanOut[T any](count int, channelsBufferCap int, upstream <-chan T) []<-chan T {
|
||||
downstreams := createChannels[T](count, channelsBufferCap)
|
||||
|
||||
go func() {
|
||||
for msg := range upstream {
|
||||
for i := range downstreams {
|
||||
downstreams[i] <- msg
|
||||
}
|
||||
}
|
||||
|
||||
// Close out once all the output goroutines are done.
|
||||
for i := range downstreams {
|
||||
close(downstreams[i])
|
||||
}
|
||||
}()
|
||||
|
||||
return channelsToReadOnly(downstreams)
|
||||
}
|
||||
136
vendor/github.com/samber/lo/concurrency.go
generated
vendored
Normal file
136
vendor/github.com/samber/lo/concurrency.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type synchronize struct {
|
||||
locker sync.Locker
|
||||
}
|
||||
|
||||
func (s *synchronize) Do(cb func()) {
|
||||
s.locker.Lock()
|
||||
Try0(cb)
|
||||
s.locker.Unlock()
|
||||
}
|
||||
|
||||
// Synchronize wraps the underlying callback in a mutex. It receives an optional mutex.
|
||||
func Synchronize(opt ...sync.Locker) *synchronize {
|
||||
if len(opt) > 1 {
|
||||
panic("unexpected arguments")
|
||||
} else if len(opt) == 0 {
|
||||
opt = append(opt, &sync.Mutex{})
|
||||
}
|
||||
|
||||
return &synchronize{
|
||||
locker: opt[0],
|
||||
}
|
||||
}
|
||||
|
||||
// Async executes a function in a goroutine and returns the result in a channel.
|
||||
func Async[A any](f func() A) <-chan A {
|
||||
ch := make(chan A, 1)
|
||||
go func() {
|
||||
ch <- f()
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Async0 executes a function in a goroutine and returns a channel set once the function finishes.
|
||||
func Async0(f func()) <-chan struct{} {
|
||||
ch := make(chan struct{}, 1)
|
||||
go func() {
|
||||
f()
|
||||
ch <- struct{}{}
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Async1 is an alias to Async.
|
||||
func Async1[A any](f func() A) <-chan A {
|
||||
return Async(f)
|
||||
}
|
||||
|
||||
// Async2 has the same behavior as Async, but returns the 2 results as a tuple inside the channel.
|
||||
func Async2[A, B any](f func() (A, B)) <-chan Tuple2[A, B] {
|
||||
ch := make(chan Tuple2[A, B], 1)
|
||||
go func() {
|
||||
ch <- T2(f())
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Async3 has the same behavior as Async, but returns the 3 results as a tuple inside the channel.
|
||||
func Async3[A, B, C any](f func() (A, B, C)) <-chan Tuple3[A, B, C] {
|
||||
ch := make(chan Tuple3[A, B, C], 1)
|
||||
go func() {
|
||||
ch <- T3(f())
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Async4 has the same behavior as Async, but returns the 4 results as a tuple inside the channel.
|
||||
func Async4[A, B, C, D any](f func() (A, B, C, D)) <-chan Tuple4[A, B, C, D] {
|
||||
ch := make(chan Tuple4[A, B, C, D], 1)
|
||||
go func() {
|
||||
ch <- T4(f())
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Async5 has the same behavior as Async, but returns the 5 results as a tuple inside the channel.
|
||||
func Async5[A, B, C, D, E any](f func() (A, B, C, D, E)) <-chan Tuple5[A, B, C, D, E] {
|
||||
ch := make(chan Tuple5[A, B, C, D, E], 1)
|
||||
go func() {
|
||||
ch <- T5(f())
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Async6 has the same behavior as Async, but returns the 6 results as a tuple inside the channel.
|
||||
func Async6[A, B, C, D, E, F any](f func() (A, B, C, D, E, F)) <-chan Tuple6[A, B, C, D, E, F] {
|
||||
ch := make(chan Tuple6[A, B, C, D, E, F], 1)
|
||||
go func() {
|
||||
ch <- T6(f())
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// WaitFor runs periodically until a condition is validated.
|
||||
func WaitFor(condition func(i int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) {
|
||||
conditionWithContext := func(_ context.Context, currentIteration int) bool {
|
||||
return condition(currentIteration)
|
||||
}
|
||||
return WaitForWithContext(context.Background(), conditionWithContext, timeout, heartbeatDelay)
|
||||
}
|
||||
|
||||
// WaitForWithContext runs periodically until a condition is validated or context is canceled.
|
||||
func WaitForWithContext(ctx context.Context, condition func(ctx context.Context, currentIteration int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) {
|
||||
start := time.Now()
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return totalIterations, time.Since(start), false
|
||||
}
|
||||
|
||||
ctx, cleanCtx := context.WithTimeout(ctx, timeout)
|
||||
ticker := time.NewTicker(heartbeatDelay)
|
||||
|
||||
defer func() {
|
||||
cleanCtx()
|
||||
ticker.Stop()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return totalIterations, time.Since(start), false
|
||||
case <-ticker.C:
|
||||
totalIterations++
|
||||
if condition(ctx, totalIterations-1) {
|
||||
return totalIterations, time.Since(start), true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
151
vendor/github.com/samber/lo/condition.go
generated
vendored
Normal file
151
vendor/github.com/samber/lo/condition.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
package lo
|
||||
|
||||
// Ternary is a 1 line if/else statement.
|
||||
// Take care to avoid dereferencing potentially nil pointers in your A/B expressions, because they are both evaluated. See TernaryF to avoid this problem.
|
||||
// Play: https://go.dev/play/p/t-D7WBL44h2
|
||||
func Ternary[T any](condition bool, ifOutput T, elseOutput T) T {
|
||||
if condition {
|
||||
return ifOutput
|
||||
}
|
||||
|
||||
return elseOutput
|
||||
}
|
||||
|
||||
// TernaryF is a 1 line if/else statement whose options are functions
|
||||
// Play: https://go.dev/play/p/AO4VW20JoqM
|
||||
func TernaryF[T any](condition bool, ifFunc func() T, elseFunc func() T) T {
|
||||
if condition {
|
||||
return ifFunc()
|
||||
}
|
||||
|
||||
return elseFunc()
|
||||
}
|
||||
|
||||
type ifElse[T any] struct {
|
||||
result T
|
||||
done bool
|
||||
}
|
||||
|
||||
// If.
|
||||
// Play: https://go.dev/play/p/WSw3ApMxhyW
|
||||
func If[T any](condition bool, result T) *ifElse[T] {
|
||||
if condition {
|
||||
return &ifElse[T]{result, true}
|
||||
}
|
||||
|
||||
var t T
|
||||
return &ifElse[T]{t, false}
|
||||
}
|
||||
|
||||
// IfF.
|
||||
// Play: https://go.dev/play/p/WSw3ApMxhyW
|
||||
func IfF[T any](condition bool, resultF func() T) *ifElse[T] {
|
||||
if condition {
|
||||
return &ifElse[T]{resultF(), true}
|
||||
}
|
||||
|
||||
var t T
|
||||
return &ifElse[T]{t, false}
|
||||
}
|
||||
|
||||
// ElseIf.
|
||||
// Play: https://go.dev/play/p/WSw3ApMxhyW
|
||||
func (i *ifElse[T]) ElseIf(condition bool, result T) *ifElse[T] {
|
||||
if !i.done && condition {
|
||||
i.result = result
|
||||
i.done = true
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// ElseIfF.
|
||||
// Play: https://go.dev/play/p/WSw3ApMxhyW
|
||||
func (i *ifElse[T]) ElseIfF(condition bool, resultF func() T) *ifElse[T] {
|
||||
if !i.done && condition {
|
||||
i.result = resultF()
|
||||
i.done = true
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// Else.
|
||||
// Play: https://go.dev/play/p/WSw3ApMxhyW
|
||||
func (i *ifElse[T]) Else(result T) T {
|
||||
if i.done {
|
||||
return i.result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ElseF.
|
||||
// Play: https://go.dev/play/p/WSw3ApMxhyW
|
||||
func (i *ifElse[T]) ElseF(resultF func() T) T {
|
||||
if i.done {
|
||||
return i.result
|
||||
}
|
||||
|
||||
return resultF()
|
||||
}
|
||||
|
||||
type switchCase[T comparable, R any] struct {
|
||||
predicate T
|
||||
result R
|
||||
done bool
|
||||
}
|
||||
|
||||
// Switch is a pure functional switch/case/default statement.
|
||||
// Play: https://go.dev/play/p/TGbKUMAeRUd
|
||||
func Switch[T comparable, R any](predicate T) *switchCase[T, R] {
|
||||
var result R
|
||||
|
||||
return &switchCase[T, R]{
|
||||
predicate,
|
||||
result,
|
||||
false,
|
||||
}
|
||||
}
|
||||
|
||||
// Case.
|
||||
// Play: https://go.dev/play/p/TGbKUMAeRUd
|
||||
func (s *switchCase[T, R]) Case(val T, result R) *switchCase[T, R] {
|
||||
if !s.done && s.predicate == val {
|
||||
s.result = result
|
||||
s.done = true
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// CaseF.
|
||||
// Play: https://go.dev/play/p/TGbKUMAeRUd
|
||||
func (s *switchCase[T, R]) CaseF(val T, cb func() R) *switchCase[T, R] {
|
||||
if !s.done && s.predicate == val {
|
||||
s.result = cb()
|
||||
s.done = true
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Default.
|
||||
// Play: https://go.dev/play/p/TGbKUMAeRUd
|
||||
func (s *switchCase[T, R]) Default(result R) R {
|
||||
if !s.done {
|
||||
s.result = result
|
||||
}
|
||||
|
||||
return s.result
|
||||
}
|
||||
|
||||
// DefaultF.
|
||||
// Play: https://go.dev/play/p/TGbKUMAeRUd
|
||||
func (s *switchCase[T, R]) DefaultF(cb func() R) R {
|
||||
if !s.done {
|
||||
s.result = cb()
|
||||
}
|
||||
|
||||
return s.result
|
||||
}
|
||||
6
vendor/github.com/samber/lo/constraints.go
generated
vendored
Normal file
6
vendor/github.com/samber/lo/constraints.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package lo
|
||||
|
||||
// Clonable defines a constraint of types having Clone() T method.
|
||||
type Clonable[T any] interface {
|
||||
Clone() T
|
||||
}
|
||||
381
vendor/github.com/samber/lo/errors.go
generated
vendored
Normal file
381
vendor/github.com/samber/lo/errors.go
generated
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const defaultAssertionFailureMessage = "assertion failed"
|
||||
|
||||
// Validate is a helper that creates an error when a condition is not met.
|
||||
// Play: https://go.dev/play/p/vPyh51XpCBt
|
||||
func Validate(ok bool, format string, args ...any) error {
|
||||
if !ok {
|
||||
return fmt.Errorf(format, args...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func messageFromMsgAndArgs(msgAndArgs ...any) string {
|
||||
if len(msgAndArgs) == 1 {
|
||||
if msgAsStr, ok := msgAndArgs[0].(string); ok {
|
||||
return msgAsStr
|
||||
}
|
||||
return fmt.Sprintf("%+v", msgAndArgs[0])
|
||||
}
|
||||
if len(msgAndArgs) > 1 {
|
||||
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// must panics if err is error or false.
|
||||
func must(err any, messageArgs ...any) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch e := err.(type) {
|
||||
case bool:
|
||||
if !e {
|
||||
message := messageFromMsgAndArgs(messageArgs...)
|
||||
if message == "" {
|
||||
message = "not ok"
|
||||
}
|
||||
|
||||
panic(message)
|
||||
}
|
||||
|
||||
case error:
|
||||
message := messageFromMsgAndArgs(messageArgs...)
|
||||
if message != "" {
|
||||
panic(message + ": " + e.Error())
|
||||
} else {
|
||||
panic(e.Error())
|
||||
}
|
||||
|
||||
default:
|
||||
panic("must: invalid err type '" + reflect.TypeOf(err).Name() + "', should either be a bool or an error")
|
||||
}
|
||||
}
|
||||
|
||||
// Must is a helper that wraps a call to a function returning a value and an error
|
||||
// and panics if err is error or false.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must[T any](val T, err any, messageArgs ...any) T {
|
||||
must(err, messageArgs...)
|
||||
return val
|
||||
}
|
||||
|
||||
// Must0 has the same behavior as Must, but callback returns no variable.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must0(err any, messageArgs ...any) {
|
||||
must(err, messageArgs...)
|
||||
}
|
||||
|
||||
// Must1 is an alias to Must
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must1[T any](val T, err any, messageArgs ...any) T {
|
||||
return Must(val, err, messageArgs...)
|
||||
}
|
||||
|
||||
// Must2 has the same behavior as Must, but callback returns 2 variables.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must2[T1, T2 any](val1 T1, val2 T2, err any, messageArgs ...any) (T1, T2) {
|
||||
must(err, messageArgs...)
|
||||
return val1, val2
|
||||
}
|
||||
|
||||
// Must3 has the same behavior as Must, but callback returns 3 variables.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must3[T1, T2, T3 any](val1 T1, val2 T2, val3 T3, err any, messageArgs ...any) (T1, T2, T3) {
|
||||
must(err, messageArgs...)
|
||||
return val1, val2, val3
|
||||
}
|
||||
|
||||
// Must4 has the same behavior as Must, but callback returns 4 variables.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must4[T1, T2, T3, T4 any](val1 T1, val2 T2, val3 T3, val4 T4, err any, messageArgs ...any) (T1, T2, T3, T4) {
|
||||
must(err, messageArgs...)
|
||||
return val1, val2, val3, val4
|
||||
}
|
||||
|
||||
// Must5 has the same behavior as Must, but callback returns 5 variables.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must5[T1, T2, T3, T4, T5 any](val1 T1, val2 T2, val3 T3, val4 T4, val5 T5, err any, messageArgs ...any) (T1, T2, T3, T4, T5) {
|
||||
must(err, messageArgs...)
|
||||
return val1, val2, val3, val4, val5
|
||||
}
|
||||
|
||||
// Must6 has the same behavior as Must, but callback returns 6 variables.
|
||||
// Play: https://go.dev/play/p/TMoWrRp3DyC
|
||||
func Must6[T1, T2, T3, T4, T5, T6 any](val1 T1, val2 T2, val3 T3, val4 T4, val5 T5, val6 T6, err any, messageArgs ...any) (T1, T2, T3, T4, T5, T6) {
|
||||
must(err, messageArgs...)
|
||||
return val1, val2, val3, val4, val5, val6
|
||||
}
|
||||
|
||||
// Try calls the function and return false in case of error.
|
||||
func Try(callback func() error) (ok bool) {
|
||||
ok = true
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
|
||||
err := callback()
|
||||
if err != nil {
|
||||
ok = false
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Try0 has the same behavior as Try, but callback returns no variable.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try0(callback func()) bool {
|
||||
return Try(func() error {
|
||||
callback()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Try1 is an alias to Try.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try1(callback func() error) bool {
|
||||
return Try(callback)
|
||||
}
|
||||
|
||||
// Try2 has the same behavior as Try, but callback returns 2 variables.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try2[T any](callback func() (T, error)) bool {
|
||||
return Try(func() error {
|
||||
_, err := callback()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// Try3 has the same behavior as Try, but callback returns 3 variables.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try3[T, R any](callback func() (T, R, error)) bool {
|
||||
return Try(func() error {
|
||||
_, _, err := callback()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// Try4 has the same behavior as Try, but callback returns 4 variables.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try4[T, R, S any](callback func() (T, R, S, error)) bool {
|
||||
return Try(func() error {
|
||||
_, _, _, err := callback()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// Try5 has the same behavior as Try, but callback returns 5 variables.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try5[T, R, S, Q any](callback func() (T, R, S, Q, error)) bool {
|
||||
return Try(func() error {
|
||||
_, _, _, _, err := callback()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// Try6 has the same behavior as Try, but callback returns 6 variables.
|
||||
// Play: https://go.dev/play/p/mTyyWUvn9u4
|
||||
func Try6[T, R, S, Q, U any](callback func() (T, R, S, Q, U, error)) bool {
|
||||
return Try(func() error {
|
||||
_, _, _, _, _, err := callback()
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// TryOr has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr[A any](callback func() (A, error), fallbackA A) (A, bool) {
|
||||
return TryOr1(callback, fallbackA)
|
||||
}
|
||||
|
||||
// TryOr1 has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr1[A any](callback func() (A, error), fallbackA A) (A, bool) {
|
||||
ok := false
|
||||
|
||||
Try0(func() {
|
||||
a, err := callback()
|
||||
if err == nil {
|
||||
fallbackA = a
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
|
||||
return fallbackA, ok
|
||||
}
|
||||
|
||||
// TryOr2 has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr2[A, B any](callback func() (A, B, error), fallbackA A, fallbackB B) (A, B, bool) {
|
||||
ok := false
|
||||
|
||||
Try0(func() {
|
||||
a, b, err := callback()
|
||||
if err == nil {
|
||||
fallbackA = a
|
||||
fallbackB = b
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
|
||||
return fallbackA, fallbackB, ok
|
||||
}
|
||||
|
||||
// TryOr3 has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr3[A, B, C any](callback func() (A, B, C, error), fallbackA A, fallbackB B, fallbackC C) (A, B, C, bool) {
|
||||
ok := false
|
||||
|
||||
Try0(func() {
|
||||
a, b, c, err := callback()
|
||||
if err == nil {
|
||||
fallbackA = a
|
||||
fallbackB = b
|
||||
fallbackC = c
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
|
||||
return fallbackA, fallbackB, fallbackC, ok
|
||||
}
|
||||
|
||||
// TryOr4 has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr4[A, B, C, D any](callback func() (A, B, C, D, error), fallbackA A, fallbackB B, fallbackC C, fallbackD D) (A, B, C, D, bool) {
|
||||
ok := false
|
||||
|
||||
Try0(func() {
|
||||
a, b, c, d, err := callback()
|
||||
if err == nil {
|
||||
fallbackA = a
|
||||
fallbackB = b
|
||||
fallbackC = c
|
||||
fallbackD = d
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
|
||||
return fallbackA, fallbackB, fallbackC, fallbackD, ok
|
||||
}
|
||||
|
||||
// TryOr5 has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr5[A, B, C, D, E any](callback func() (A, B, C, D, E, error), fallbackA A, fallbackB B, fallbackC C, fallbackD D, fallbackE E) (A, B, C, D, E, bool) {
|
||||
ok := false
|
||||
|
||||
Try0(func() {
|
||||
a, b, c, d, e, err := callback()
|
||||
if err == nil {
|
||||
fallbackA = a
|
||||
fallbackB = b
|
||||
fallbackC = c
|
||||
fallbackD = d
|
||||
fallbackE = e
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
|
||||
return fallbackA, fallbackB, fallbackC, fallbackD, fallbackE, ok
|
||||
}
|
||||
|
||||
// TryOr6 has the same behavior as Must, but returns a default value in case of error.
|
||||
// Play: https://go.dev/play/p/B4F7Wg2Zh9X
|
||||
func TryOr6[A, B, C, D, E, F any](callback func() (A, B, C, D, E, F, error), fallbackA A, fallbackB B, fallbackC C, fallbackD D, fallbackE E, fallbackF F) (A, B, C, D, E, F, bool) {
|
||||
ok := false
|
||||
|
||||
Try0(func() {
|
||||
a, b, c, d, e, f, err := callback()
|
||||
if err == nil {
|
||||
fallbackA = a
|
||||
fallbackB = b
|
||||
fallbackC = c
|
||||
fallbackD = d
|
||||
fallbackE = e
|
||||
fallbackF = f
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
|
||||
return fallbackA, fallbackB, fallbackC, fallbackD, fallbackE, fallbackF, ok
|
||||
}
|
||||
|
||||
// TryWithErrorValue has the same behavior as Try, but also returns value passed to panic.
|
||||
// Play: https://go.dev/play/p/Kc7afQIT2Fs
|
||||
func TryWithErrorValue(callback func() error) (errorValue any, ok bool) {
|
||||
ok = true
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ok = false
|
||||
errorValue = r
|
||||
}
|
||||
}()
|
||||
|
||||
err := callback()
|
||||
if err != nil {
|
||||
ok = false
|
||||
errorValue = err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TryCatch has the same behavior as Try, but calls the catch function in case of error.
|
||||
// Play: https://go.dev/play/p/PnOON-EqBiU
|
||||
func TryCatch(callback func() error, catch func()) {
|
||||
if !Try(callback) {
|
||||
catch()
|
||||
}
|
||||
}
|
||||
|
||||
// TryCatchWithErrorValue has the same behavior as TryWithErrorValue, but calls the catch function in case of error.
|
||||
// Play: https://go.dev/play/p/8Pc9gwX_GZO
|
||||
func TryCatchWithErrorValue(callback func() error, catch func(any)) {
|
||||
if err, ok := TryWithErrorValue(callback); !ok {
|
||||
catch(err)
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorsAs is a shortcut for errors.As(err, &&T).
|
||||
// Play: https://go.dev/play/p/8wk5rH8UfrE
|
||||
func ErrorsAs[T error](err error) (T, bool) {
|
||||
var t T
|
||||
ok := errors.As(err, &t)
|
||||
return t, ok
|
||||
}
|
||||
|
||||
// Assert does nothing when the condition is true, otherwise it panics with an optional message.
|
||||
// Play: https://go.dev/play/p/Xv8LLKBMNwI
|
||||
func Assert(condition bool, message ...string) {
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
|
||||
panicMessage := defaultAssertionFailureMessage
|
||||
if len(message) > 0 {
|
||||
panicMessage = fmt.Sprintf("%s: %s", defaultAssertionFailureMessage, message[0])
|
||||
}
|
||||
panic(panicMessage)
|
||||
}
|
||||
|
||||
// Assertf does nothing when the condition is true, otherwise it panics with a formatted message.
|
||||
// Play: https://go.dev/play/p/TVPEmVcyrdY
|
||||
func Assertf(condition bool, format string, args ...any) {
|
||||
if condition {
|
||||
return
|
||||
}
|
||||
|
||||
panicMessage := fmt.Sprintf("%s: %s", defaultAssertionFailureMessage, fmt.Sprintf(format, args...))
|
||||
panic(panicMessage)
|
||||
}
|
||||
651
vendor/github.com/samber/lo/find.go
generated
vendored
Normal file
651
vendor/github.com/samber/lo/find.go
generated
vendored
Normal file
@@ -0,0 +1,651 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo/internal/constraints"
|
||||
"github.com/samber/lo/internal/rand"
|
||||
)
|
||||
|
||||
// IndexOf returns the index at which the first occurrence of a value is found in an array or return -1
|
||||
// if the value cannot be found.
|
||||
func IndexOf[T comparable](collection []T, element T) int {
|
||||
for i := range collection {
|
||||
if collection[i] == element {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index at which the last occurrence of a value is found in an array or return -1
|
||||
// if the value cannot be found.
|
||||
func LastIndexOf[T comparable](collection []T, element T) int {
|
||||
length := len(collection)
|
||||
|
||||
for i := length - 1; i >= 0; i-- {
|
||||
if collection[i] == element {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// Find search an element in a slice based on a predicate. It returns element and true if element was found.
|
||||
func Find[T any](collection []T, predicate func(item T) bool) (T, bool) {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
return collection[i], true
|
||||
}
|
||||
}
|
||||
|
||||
var result T
|
||||
return result, false
|
||||
}
|
||||
|
||||
// FindIndexOf searches an element in a slice based on a predicate and returns the index and true.
|
||||
// It returns -1 and false if the element is not found.
|
||||
func FindIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bool) {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
return collection[i], i, true
|
||||
}
|
||||
}
|
||||
|
||||
var result T
|
||||
return result, -1, false
|
||||
}
|
||||
|
||||
// FindLastIndexOf searches last element in a slice based on a predicate and returns the index and true.
|
||||
// It returns -1 and false if the element is not found.
|
||||
func FindLastIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bool) {
|
||||
length := len(collection)
|
||||
|
||||
for i := length - 1; i >= 0; i-- {
|
||||
if predicate(collection[i]) {
|
||||
return collection[i], i, true
|
||||
}
|
||||
}
|
||||
|
||||
var result T
|
||||
return result, -1, false
|
||||
}
|
||||
|
||||
// FindOrElse search an element in a slice based on a predicate. It returns the element if found or a given fallback value otherwise.
|
||||
func FindOrElse[T any](collection []T, fallback T, predicate func(item T) bool) T {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
return collection[i]
|
||||
}
|
||||
}
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
// FindKey returns the key of the first value matching.
|
||||
func FindKey[K comparable, V comparable](object map[K]V, value V) (K, bool) {
|
||||
for k := range object {
|
||||
if object[k] == value {
|
||||
return k, true
|
||||
}
|
||||
}
|
||||
|
||||
return Empty[K](), false
|
||||
}
|
||||
|
||||
// FindKeyBy returns the key of the first element predicate returns truthy for.
|
||||
func FindKeyBy[K comparable, V any](object map[K]V, predicate func(key K, value V) bool) (K, bool) {
|
||||
for k := range object {
|
||||
if predicate(k, object[k]) {
|
||||
return k, true
|
||||
}
|
||||
}
|
||||
|
||||
return Empty[K](), false
|
||||
}
|
||||
|
||||
// FindUniques returns a slice with all the unique elements of the collection.
|
||||
// The order of result values is determined by the order they occur in the collection.
|
||||
func FindUniques[T comparable, Slice ~[]T](collection Slice) Slice {
|
||||
isDupl := make(map[T]bool, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
duplicated, ok := isDupl[collection[i]]
|
||||
if !ok {
|
||||
isDupl[collection[i]] = false
|
||||
} else if !duplicated {
|
||||
isDupl[collection[i]] = true
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-len(isDupl))
|
||||
|
||||
for i := range collection {
|
||||
if duplicated := isDupl[collection[i]]; !duplicated {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FindUniquesBy returns a slice with all the unique elements of the collection.
|
||||
// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is
|
||||
// invoked for each element in array to generate the criterion by which uniqueness is computed.
|
||||
func FindUniquesBy[T any, U comparable, Slice ~[]T](collection Slice, iteratee func(item T) U) Slice {
|
||||
isDupl := make(map[U]bool, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
duplicated, ok := isDupl[key]
|
||||
if !ok {
|
||||
isDupl[key] = false
|
||||
} else if !duplicated {
|
||||
isDupl[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-len(isDupl))
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
if duplicated := isDupl[key]; !duplicated {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FindDuplicates returns a slice with the first occurrence of each duplicated elements of the collection.
|
||||
// The order of result values is determined by the order they occur in the collection.
|
||||
func FindDuplicates[T comparable, Slice ~[]T](collection Slice) Slice {
|
||||
isDupl := make(map[T]bool, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
duplicated, ok := isDupl[collection[i]]
|
||||
if !ok {
|
||||
isDupl[collection[i]] = false
|
||||
} else if !duplicated {
|
||||
isDupl[collection[i]] = true
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-len(isDupl))
|
||||
|
||||
for i := range collection {
|
||||
if duplicated := isDupl[collection[i]]; duplicated {
|
||||
result = append(result, collection[i])
|
||||
isDupl[collection[i]] = false
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FindDuplicatesBy returns a slice with the first occurrence of each duplicated elements of the collection.
|
||||
// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is
|
||||
// invoked for each element in array to generate the criterion by which uniqueness is computed.
|
||||
func FindDuplicatesBy[T any, U comparable, Slice ~[]T](collection Slice, iteratee func(item T) U) Slice {
|
||||
isDupl := make(map[U]bool, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
duplicated, ok := isDupl[key]
|
||||
if !ok {
|
||||
isDupl[key] = false
|
||||
} else if !duplicated {
|
||||
isDupl[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-len(isDupl))
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
if duplicated := isDupl[key]; duplicated {
|
||||
result = append(result, collection[i])
|
||||
isDupl[key] = false
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Min search the minimum value of a collection.
|
||||
// Returns zero value when the collection is empty.
|
||||
func Min[T constraints.Ordered](collection []T) T {
|
||||
var min T
|
||||
|
||||
if len(collection) == 0 {
|
||||
return min
|
||||
}
|
||||
|
||||
min = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if item < min {
|
||||
min = item
|
||||
}
|
||||
}
|
||||
|
||||
return min
|
||||
}
|
||||
|
||||
// MinIndex search the minimum value of a collection and the index of the minimum value.
|
||||
// Returns (zero value, -1) when the collection is empty.
|
||||
func MinIndex[T constraints.Ordered](collection []T) (T, int) {
|
||||
var (
|
||||
min T
|
||||
index int
|
||||
)
|
||||
|
||||
if len(collection) == 0 {
|
||||
return min, -1
|
||||
}
|
||||
|
||||
min = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if item < min {
|
||||
min = item
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return min, index
|
||||
}
|
||||
|
||||
// MinBy search the minimum value of a collection using the given comparison function.
|
||||
// If several values of the collection are equal to the smallest value, returns the first such value.
|
||||
// Returns zero value when the collection is empty.
|
||||
func MinBy[T any](collection []T, comparison func(a T, b T) bool) T {
|
||||
var min T
|
||||
|
||||
if len(collection) == 0 {
|
||||
return min
|
||||
}
|
||||
|
||||
min = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if comparison(item, min) {
|
||||
min = item
|
||||
}
|
||||
}
|
||||
|
||||
return min
|
||||
}
|
||||
|
||||
// MinIndexBy search the minimum value of a collection using the given comparison function and the index of the minimum value.
|
||||
// If several values of the collection are equal to the smallest value, returns the first such value.
|
||||
// Returns (zero value, -1) when the collection is empty.
|
||||
func MinIndexBy[T any](collection []T, comparison func(a T, b T) bool) (T, int) {
|
||||
var (
|
||||
min T
|
||||
index int
|
||||
)
|
||||
|
||||
if len(collection) == 0 {
|
||||
return min, -1
|
||||
}
|
||||
|
||||
min = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if comparison(item, min) {
|
||||
min = item
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return min, index
|
||||
}
|
||||
|
||||
// Earliest search the minimum time.Time of a collection.
|
||||
// Returns zero value when the collection is empty.
|
||||
func Earliest(times ...time.Time) time.Time {
|
||||
var min time.Time
|
||||
|
||||
if len(times) == 0 {
|
||||
return min
|
||||
}
|
||||
|
||||
min = times[0]
|
||||
|
||||
for i := 1; i < len(times); i++ {
|
||||
item := times[i]
|
||||
|
||||
if item.Before(min) {
|
||||
min = item
|
||||
}
|
||||
}
|
||||
|
||||
return min
|
||||
}
|
||||
|
||||
// EarliestBy search the minimum time.Time of a collection using the given iteratee function.
|
||||
// Returns zero value when the collection is empty.
|
||||
func EarliestBy[T any](collection []T, iteratee func(item T) time.Time) T {
|
||||
var earliest T
|
||||
|
||||
if len(collection) == 0 {
|
||||
return earliest
|
||||
}
|
||||
|
||||
earliest = collection[0]
|
||||
earliestTime := iteratee(collection[0])
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
itemTime := iteratee(collection[i])
|
||||
|
||||
if itemTime.Before(earliestTime) {
|
||||
earliest = collection[i]
|
||||
earliestTime = itemTime
|
||||
}
|
||||
}
|
||||
|
||||
return earliest
|
||||
}
|
||||
|
||||
// Max searches the maximum value of a collection.
|
||||
// Returns zero value when the collection is empty.
|
||||
func Max[T constraints.Ordered](collection []T) T {
|
||||
var max T
|
||||
|
||||
if len(collection) == 0 {
|
||||
return max
|
||||
}
|
||||
|
||||
max = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if item > max {
|
||||
max = item
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
// MaxIndex searches the maximum value of a collection and the index of the maximum value.
|
||||
// Returns (zero value, -1) when the collection is empty.
|
||||
func MaxIndex[T constraints.Ordered](collection []T) (T, int) {
|
||||
var (
|
||||
max T
|
||||
index int
|
||||
)
|
||||
|
||||
if len(collection) == 0 {
|
||||
return max, -1
|
||||
}
|
||||
|
||||
max = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if item > max {
|
||||
max = item
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return max, index
|
||||
}
|
||||
|
||||
// MaxBy search the maximum value of a collection using the given comparison function.
|
||||
// If several values of the collection are equal to the greatest value, returns the first such value.
|
||||
// Returns zero value when the collection is empty.
|
||||
func MaxBy[T any](collection []T, comparison func(a T, b T) bool) T {
|
||||
var max T
|
||||
|
||||
if len(collection) == 0 {
|
||||
return max
|
||||
}
|
||||
|
||||
max = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if comparison(item, max) {
|
||||
max = item
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
// MaxIndexBy search the maximum value of a collection using the given comparison function and the index of the maximum value.
|
||||
// If several values of the collection are equal to the greatest value, returns the first such value.
|
||||
// Returns (zero value, -1) when the collection is empty.
|
||||
func MaxIndexBy[T any](collection []T, comparison func(a T, b T) bool) (T, int) {
|
||||
var (
|
||||
max T
|
||||
index int
|
||||
)
|
||||
|
||||
if len(collection) == 0 {
|
||||
return max, -1
|
||||
}
|
||||
|
||||
max = collection[0]
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
item := collection[i]
|
||||
|
||||
if comparison(item, max) {
|
||||
max = item
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
return max, index
|
||||
}
|
||||
|
||||
// Latest search the maximum time.Time of a collection.
|
||||
// Returns zero value when the collection is empty.
|
||||
func Latest(times ...time.Time) time.Time {
|
||||
var max time.Time
|
||||
|
||||
if len(times) == 0 {
|
||||
return max
|
||||
}
|
||||
|
||||
max = times[0]
|
||||
|
||||
for i := 1; i < len(times); i++ {
|
||||
item := times[i]
|
||||
|
||||
if item.After(max) {
|
||||
max = item
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
|
||||
// LatestBy search the maximum time.Time of a collection using the given iteratee function.
|
||||
// Returns zero value when the collection is empty.
|
||||
func LatestBy[T any](collection []T, iteratee func(item T) time.Time) T {
|
||||
var latest T
|
||||
|
||||
if len(collection) == 0 {
|
||||
return latest
|
||||
}
|
||||
|
||||
latest = collection[0]
|
||||
latestTime := iteratee(collection[0])
|
||||
|
||||
for i := 1; i < len(collection); i++ {
|
||||
itemTime := iteratee(collection[i])
|
||||
|
||||
if itemTime.After(latestTime) {
|
||||
latest = collection[i]
|
||||
latestTime = itemTime
|
||||
}
|
||||
}
|
||||
|
||||
return latest
|
||||
}
|
||||
|
||||
// First returns the first element of a collection and check for availability of the first element.
|
||||
func First[T any](collection []T) (T, bool) {
|
||||
length := len(collection)
|
||||
|
||||
if length == 0 {
|
||||
var t T
|
||||
return t, false
|
||||
}
|
||||
|
||||
return collection[0], true
|
||||
}
|
||||
|
||||
// FirstOrEmpty returns the first element of a collection or zero value if empty.
|
||||
func FirstOrEmpty[T any](collection []T) T {
|
||||
i, _ := First(collection)
|
||||
return i
|
||||
}
|
||||
|
||||
// FirstOr returns the first element of a collection or the fallback value if empty.
|
||||
func FirstOr[T any](collection []T, fallback T) T {
|
||||
i, ok := First(collection)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// Last returns the last element of a collection or error if empty.
|
||||
func Last[T any](collection []T) (T, bool) {
|
||||
length := len(collection)
|
||||
|
||||
if length == 0 {
|
||||
var t T
|
||||
return t, false
|
||||
}
|
||||
|
||||
return collection[length-1], true
|
||||
}
|
||||
|
||||
// LastOrEmpty returns the last element of a collection or zero value if empty.
|
||||
func LastOrEmpty[T any](collection []T) T {
|
||||
i, _ := Last(collection)
|
||||
return i
|
||||
}
|
||||
|
||||
// LastOr returns the last element of a collection or the fallback value if empty.
|
||||
func LastOr[T any](collection []T, fallback T) T {
|
||||
i, ok := Last(collection)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
// Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element
|
||||
// from the end is returned. An error is returned when nth is out of slice bounds.
|
||||
func Nth[T any, N constraints.Integer](collection []T, nth N) (T, error) {
|
||||
n := int(nth)
|
||||
l := len(collection)
|
||||
if n >= l || -n > l {
|
||||
var t T
|
||||
return t, fmt.Errorf("nth: %d out of slice bounds", n)
|
||||
}
|
||||
|
||||
if n >= 0 {
|
||||
return collection[n], nil
|
||||
}
|
||||
return collection[l+n], nil
|
||||
}
|
||||
|
||||
// NthOr returns the element at index `nth` of collection.
|
||||
// If `nth` is negative, it returns the nth element from the end.
|
||||
// If `nth` is out of slice bounds, it returns the fallback value instead of an error.
|
||||
func NthOr[T any, N constraints.Integer](collection []T, nth N, fallback T) T {
|
||||
value, err := Nth(collection, nth)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// NthOrEmpty returns the element at index `nth` of collection.
|
||||
// If `nth` is negative, it returns the nth element from the end.
|
||||
// If `nth` is out of slice bounds, it returns the zero value (empty value) for that type.
|
||||
func NthOrEmpty[T any, N constraints.Integer](collection []T, nth N) T {
|
||||
value, err := Nth(collection, nth)
|
||||
if err != nil {
|
||||
var zeroValue T
|
||||
return zeroValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// randomIntGenerator is a function that should return a random integer in the range [0, n)
|
||||
// where n is the parameter passed to the randomIntGenerator.
|
||||
type randomIntGenerator func(n int) int
|
||||
|
||||
// Sample returns a random item from collection.
|
||||
func Sample[T any](collection []T) T {
|
||||
result := SampleBy(collection, rand.IntN)
|
||||
return result
|
||||
}
|
||||
|
||||
// SampleBy returns a random item from collection, using randomIntGenerator as the random index generator.
|
||||
func SampleBy[T any](collection []T, randomIntGenerator randomIntGenerator) T {
|
||||
size := len(collection)
|
||||
if size == 0 {
|
||||
return Empty[T]()
|
||||
}
|
||||
return collection[randomIntGenerator(size)]
|
||||
}
|
||||
|
||||
// Samples returns N random unique items from collection.
|
||||
func Samples[T any, Slice ~[]T](collection Slice, count int) Slice {
|
||||
results := SamplesBy(collection, count, rand.IntN)
|
||||
return results
|
||||
}
|
||||
|
||||
// SamplesBy returns N random unique items from collection, using randomIntGenerator as the random index generator.
|
||||
func SamplesBy[T any, Slice ~[]T](collection Slice, count int, randomIntGenerator randomIntGenerator) Slice {
|
||||
size := len(collection)
|
||||
|
||||
copy := append(Slice{}, collection...)
|
||||
|
||||
results := Slice{}
|
||||
|
||||
for i := 0; i < size && i < count; i++ {
|
||||
copyLength := size - i
|
||||
|
||||
index := randomIntGenerator(size - i)
|
||||
results = append(results, copy[index])
|
||||
|
||||
// Removes element.
|
||||
// It is faster to swap with last element and remove it.
|
||||
copy[index] = copy[copyLength-1]
|
||||
copy = copy[:copyLength-1]
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
41
vendor/github.com/samber/lo/func.go
generated
vendored
Normal file
41
vendor/github.com/samber/lo/func.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package lo
|
||||
|
||||
// Partial returns new function that, when called, has its first argument set to the provided value.
|
||||
func Partial[T1, T2, R any](f func(a T1, b T2) R, arg1 T1) func(T2) R {
|
||||
return func(t2 T2) R {
|
||||
return f(arg1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
// Partial1 returns new function that, when called, has its first argument set to the provided value.
|
||||
func Partial1[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R {
|
||||
return Partial(f, arg1)
|
||||
}
|
||||
|
||||
// Partial2 returns new function that, when called, has its first argument set to the provided value.
|
||||
func Partial2[T1, T2, T3, R any](f func(T1, T2, T3) R, arg1 T1) func(T2, T3) R {
|
||||
return func(t2 T2, t3 T3) R {
|
||||
return f(arg1, t2, t3)
|
||||
}
|
||||
}
|
||||
|
||||
// Partial3 returns new function that, when called, has its first argument set to the provided value.
|
||||
func Partial3[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) R, arg1 T1) func(T2, T3, T4) R {
|
||||
return func(t2 T2, t3 T3, t4 T4) R {
|
||||
return f(arg1, t2, t3, t4)
|
||||
}
|
||||
}
|
||||
|
||||
// Partial4 returns new function that, when called, has its first argument set to the provided value.
|
||||
func Partial4[T1, T2, T3, T4, T5, R any](f func(T1, T2, T3, T4, T5) R, arg1 T1) func(T2, T3, T4, T5) R {
|
||||
return func(t2 T2, t3 T3, t4 T4, t5 T5) R {
|
||||
return f(arg1, t2, t3, t4, t5)
|
||||
}
|
||||
}
|
||||
|
||||
// Partial5 returns new function that, when called, has its first argument set to the provided value
|
||||
func Partial5[T1, T2, T3, T4, T5, T6, R any](f func(T1, T2, T3, T4, T5, T6) R, arg1 T1) func(T2, T3, T4, T5, T6) R {
|
||||
return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R {
|
||||
return f(arg1, t2, t3, t4, t5, t6)
|
||||
}
|
||||
}
|
||||
42
vendor/github.com/samber/lo/internal/constraints/constraints.go
generated
vendored
Normal file
42
vendor/github.com/samber/lo/internal/constraints/constraints.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package 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
|
||||
}
|
||||
11
vendor/github.com/samber/lo/internal/constraints/ordered_go118.go
generated
vendored
Normal file
11
vendor/github.com/samber/lo/internal/constraints/ordered_go118.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build !go1.21
|
||||
|
||||
package constraints
|
||||
|
||||
// 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
|
||||
}
|
||||
9
vendor/github.com/samber/lo/internal/constraints/ordered_go121.go
generated
vendored
Normal file
9
vendor/github.com/samber/lo/internal/constraints/ordered_go121.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build go1.21
|
||||
|
||||
package constraints
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
)
|
||||
|
||||
type Ordered = cmp.Ordered
|
||||
26
vendor/github.com/samber/lo/internal/rand/ordered_go118.go
generated
vendored
Normal file
26
vendor/github.com/samber/lo/internal/rand/ordered_go118.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build !go1.22
|
||||
|
||||
package rand
|
||||
|
||||
import "math/rand"
|
||||
|
||||
func Shuffle(n int, swap func(i, j int)) {
|
||||
rand.Shuffle(n, swap)
|
||||
}
|
||||
|
||||
func IntN(n int) int {
|
||||
// bearer:disable go_gosec_crypto_weak_random
|
||||
return rand.Intn(n)
|
||||
}
|
||||
|
||||
func Int64() int64 {
|
||||
// bearer:disable go_gosec_crypto_weak_random
|
||||
n := rand.Int63()
|
||||
|
||||
// bearer:disable go_gosec_crypto_weak_random
|
||||
if rand.Intn(2) == 0 {
|
||||
return -n
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
17
vendor/github.com/samber/lo/internal/rand/ordered_go122.go
generated
vendored
Normal file
17
vendor/github.com/samber/lo/internal/rand/ordered_go122.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
//go:build go1.22
|
||||
|
||||
package rand
|
||||
|
||||
import "math/rand/v2"
|
||||
|
||||
func Shuffle(n int, swap func(i, j int)) {
|
||||
rand.Shuffle(n, swap)
|
||||
}
|
||||
|
||||
func IntN(n int) int {
|
||||
return rand.IntN(n)
|
||||
}
|
||||
|
||||
func Int64() int64 {
|
||||
return rand.Int64()
|
||||
}
|
||||
265
vendor/github.com/samber/lo/intersect.go
generated
vendored
Normal file
265
vendor/github.com/samber/lo/intersect.go
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
package lo
|
||||
|
||||
// Contains returns true if an element is present in a collection.
|
||||
func Contains[T comparable](collection []T, element T) bool {
|
||||
for i := range collection {
|
||||
if collection[i] == element {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainsBy returns true if predicate function return true.
|
||||
func ContainsBy[T any](collection []T, predicate func(item T) bool) bool {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Every returns true if all elements of a subset are contained into a collection or if the subset is empty.
|
||||
func Every[T comparable](collection []T, subset []T) bool {
|
||||
for i := range subset {
|
||||
if !Contains(collection, subset[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// EveryBy returns true if the predicate returns true for all elements in the collection or if the collection is empty.
|
||||
func EveryBy[T any](collection []T, predicate func(item T) bool) bool {
|
||||
for i := range collection {
|
||||
if !predicate(collection[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Some returns true if at least 1 element of a subset is contained into a collection.
|
||||
// If the subset is empty Some returns false.
|
||||
func Some[T comparable](collection []T, subset []T) bool {
|
||||
for i := range subset {
|
||||
if Contains(collection, subset[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SomeBy returns true if the predicate returns true for any of the elements in the collection.
|
||||
// If the collection is empty SomeBy returns false.
|
||||
func SomeBy[T any](collection []T, predicate func(item T) bool) bool {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// None returns true if no element of a subset are contained into a collection or if the subset is empty.
|
||||
func None[T comparable](collection []T, subset []T) bool {
|
||||
for i := range subset {
|
||||
if Contains(collection, subset[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// NoneBy returns true if the predicate returns true for none of the elements in the collection or if the collection is empty.
|
||||
func NoneBy[T any](collection []T, predicate func(item T) bool) bool {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersect returns the intersection between two collections.
|
||||
func Intersect[T comparable, Slice ~[]T](list1 Slice, list2 Slice) Slice {
|
||||
result := Slice{}
|
||||
seen := map[T]struct{}{}
|
||||
|
||||
for i := range list1 {
|
||||
seen[list1[i]] = struct{}{}
|
||||
}
|
||||
|
||||
for i := range list2 {
|
||||
if _, ok := seen[list2[i]]; ok {
|
||||
result = append(result, list2[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference returns the difference between two collections.
|
||||
// The first value is the collection of element absent of list2.
|
||||
// The second value is the collection of element absent of list1.
|
||||
func Difference[T comparable, Slice ~[]T](list1 Slice, list2 Slice) (Slice, Slice) {
|
||||
left := Slice{}
|
||||
right := Slice{}
|
||||
|
||||
seenLeft := map[T]struct{}{}
|
||||
seenRight := map[T]struct{}{}
|
||||
|
||||
for i := range list1 {
|
||||
seenLeft[list1[i]] = struct{}{}
|
||||
}
|
||||
|
||||
for i := range list2 {
|
||||
seenRight[list2[i]] = struct{}{}
|
||||
}
|
||||
|
||||
for i := range list1 {
|
||||
if _, ok := seenRight[list1[i]]; !ok {
|
||||
left = append(left, list1[i])
|
||||
}
|
||||
}
|
||||
|
||||
for i := range list2 {
|
||||
if _, ok := seenLeft[list2[i]]; !ok {
|
||||
right = append(right, list2[i])
|
||||
}
|
||||
}
|
||||
|
||||
return left, right
|
||||
}
|
||||
|
||||
// Union returns all distinct elements from given collections.
|
||||
// result returns will not change the order of elements relatively.
|
||||
func Union[T comparable, Slice ~[]T](lists ...Slice) Slice {
|
||||
var capLen int
|
||||
|
||||
for _, list := range lists {
|
||||
capLen += len(list)
|
||||
}
|
||||
|
||||
result := make(Slice, 0, capLen)
|
||||
seen := make(map[T]struct{}, capLen)
|
||||
|
||||
for i := range lists {
|
||||
for j := range lists[i] {
|
||||
if _, ok := seen[lists[i][j]]; !ok {
|
||||
seen[lists[i][j]] = struct{}{}
|
||||
result = append(result, lists[i][j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Without returns slice excluding all given values.
|
||||
func Without[T comparable, Slice ~[]T](collection Slice, exclude ...T) Slice {
|
||||
excludeMap := make(map[T]struct{}, len(exclude))
|
||||
for i := range exclude {
|
||||
excludeMap[exclude[i]] = struct{}{}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection))
|
||||
for i := range collection {
|
||||
if _, ok := excludeMap[collection[i]]; !ok {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// WithoutBy filters a slice by excluding elements whose extracted keys match any in the exclude list.
|
||||
// It returns a new slice containing only the elements whose keys are not in the exclude list.
|
||||
func WithoutBy[T any, K comparable](collection []T, iteratee func(item T) K, exclude ...K) []T {
|
||||
excludeMap := make(map[K]struct{}, len(exclude))
|
||||
for _, e := range exclude {
|
||||
excludeMap[e] = struct{}{}
|
||||
}
|
||||
|
||||
result := make([]T, 0, len(collection))
|
||||
for _, item := range collection {
|
||||
if _, ok := excludeMap[iteratee(item)]; !ok {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// WithoutEmpty returns slice excluding zero values.
|
||||
//
|
||||
// Deprecated: Use lo.Compact instead.
|
||||
func WithoutEmpty[T comparable, Slice ~[]T](collection Slice) Slice {
|
||||
return Compact(collection)
|
||||
}
|
||||
|
||||
// WithoutNth returns slice excluding nth value.
|
||||
func WithoutNth[T comparable, Slice ~[]T](collection Slice, nths ...int) Slice {
|
||||
length := len(collection)
|
||||
|
||||
toRemove := make(map[int]struct{}, len(nths))
|
||||
for i := range nths {
|
||||
if nths[i] >= 0 && nths[i] <= length-1 {
|
||||
toRemove[nths[i]] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection))
|
||||
for i := range collection {
|
||||
if _, ok := toRemove[i]; !ok {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ElementsMatch returns true if lists contain the same set of elements (including empty set).
|
||||
// If there are duplicate elements, the number of appearances of each of them in both lists should match.
|
||||
// The order of elements is not checked.
|
||||
func ElementsMatch[T comparable, Slice ~[]T](list1 Slice, list2 Slice) bool {
|
||||
return ElementsMatchBy(list1, list2, func(item T) T { return item })
|
||||
}
|
||||
|
||||
// ElementsMatchBy returns true if lists contain the same set of elements' keys (including empty set).
|
||||
// If there are duplicate keys, the number of appearances of each of them in both lists should match.
|
||||
// The order of elements is not checked.
|
||||
func ElementsMatchBy[T any, K comparable](list1 []T, list2 []T, iteratee func(item T) K) bool {
|
||||
if len(list1) != len(list2) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(list1) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
counters := make(map[K]int, len(list1))
|
||||
|
||||
for _, el := range list1 {
|
||||
counters[iteratee(el)]++
|
||||
}
|
||||
|
||||
for _, el := range list2 {
|
||||
counters[iteratee(el)]--
|
||||
}
|
||||
|
||||
for _, count := range counters {
|
||||
if count != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
344
vendor/github.com/samber/lo/map.go
generated
vendored
Normal file
344
vendor/github.com/samber/lo/map.go
generated
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
package lo
|
||||
|
||||
// Keys creates an array of the map keys.
|
||||
// Play: https://go.dev/play/p/Uu11fHASqrU
|
||||
func Keys[K comparable, V any](in ...map[K]V) []K {
|
||||
size := 0
|
||||
for i := range in {
|
||||
size += len(in[i])
|
||||
}
|
||||
result := make([]K, 0, size)
|
||||
|
||||
for i := range in {
|
||||
for k := range in[i] {
|
||||
result = append(result, k)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqKeys creates an array of unique keys in the map.
|
||||
// Play: https://go.dev/play/p/TPKAb6ILdHk
|
||||
func UniqKeys[K comparable, V any](in ...map[K]V) []K {
|
||||
size := 0
|
||||
for i := range in {
|
||||
size += len(in[i])
|
||||
}
|
||||
|
||||
seen := make(map[K]struct{}, size)
|
||||
result := make([]K, 0)
|
||||
|
||||
for i := range in {
|
||||
for k := range in[i] {
|
||||
if _, exists := seen[k]; exists {
|
||||
continue
|
||||
}
|
||||
seen[k] = struct{}{}
|
||||
result = append(result, k)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// HasKey returns whether the given key exists.
|
||||
// Play: https://go.dev/play/p/aVwubIvECqS
|
||||
func HasKey[K comparable, V any](in map[K]V, key K) bool {
|
||||
_, ok := in[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Values creates an array of the map values.
|
||||
// Play: https://go.dev/play/p/nnRTQkzQfF6
|
||||
func Values[K comparable, V any](in ...map[K]V) []V {
|
||||
size := 0
|
||||
for i := range in {
|
||||
size += len(in[i])
|
||||
}
|
||||
result := make([]V, 0, size)
|
||||
|
||||
for i := range in {
|
||||
for k := range in[i] {
|
||||
result = append(result, in[i][k])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqValues creates an array of unique values in the map.
|
||||
// Play: https://go.dev/play/p/nf6bXMh7rM3
|
||||
func UniqValues[K comparable, V comparable](in ...map[K]V) []V {
|
||||
size := 0
|
||||
for i := range in {
|
||||
size += len(in[i])
|
||||
}
|
||||
|
||||
seen := make(map[V]struct{}, size)
|
||||
result := make([]V, 0)
|
||||
|
||||
for i := range in {
|
||||
for k := range in[i] {
|
||||
val := in[i][k]
|
||||
if _, exists := seen[val]; exists {
|
||||
continue
|
||||
}
|
||||
seen[val] = struct{}{}
|
||||
result = append(result, val)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ValueOr returns the value of the given key or the fallback value if the key is not present.
|
||||
// Play: https://go.dev/play/p/bAq9mHErB4V
|
||||
func ValueOr[K comparable, V any](in map[K]V, key K, fallback V) V {
|
||||
if v, ok := in[key]; ok {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
// PickBy returns same map type filtered by given predicate.
|
||||
// Play: https://go.dev/play/p/kdg8GR_QMmf
|
||||
func PickBy[K comparable, V any, Map ~map[K]V](in Map, predicate func(key K, value V) bool) Map {
|
||||
r := Map{}
|
||||
for k := range in {
|
||||
if predicate(k, in[k]) {
|
||||
r[k] = in[k]
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// PickByKeys returns same map type filtered by given keys.
|
||||
// Play: https://go.dev/play/p/R1imbuci9qU
|
||||
func PickByKeys[K comparable, V any, Map ~map[K]V](in Map, keys []K) Map {
|
||||
r := Map{}
|
||||
for i := range keys {
|
||||
if v, ok := in[keys[i]]; ok {
|
||||
r[keys[i]] = v
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// PickByValues returns same map type filtered by given values.
|
||||
// Play: https://go.dev/play/p/1zdzSvbfsJc
|
||||
func PickByValues[K comparable, V comparable, Map ~map[K]V](in Map, values []V) Map {
|
||||
r := Map{}
|
||||
for k := range in {
|
||||
if Contains(values, in[k]) {
|
||||
r[k] = in[k]
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// OmitBy returns same map type filtered by given predicate.
|
||||
// Play: https://go.dev/play/p/EtBsR43bdsd
|
||||
func OmitBy[K comparable, V any, Map ~map[K]V](in Map, predicate func(key K, value V) bool) Map {
|
||||
r := Map{}
|
||||
for k := range in {
|
||||
if !predicate(k, in[k]) {
|
||||
r[k] = in[k]
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// OmitByKeys returns same map type filtered by given keys.
|
||||
// Play: https://go.dev/play/p/t1QjCrs-ysk
|
||||
func OmitByKeys[K comparable, V any, Map ~map[K]V](in Map, keys []K) Map {
|
||||
r := Map{}
|
||||
for k := range in {
|
||||
r[k] = in[k]
|
||||
}
|
||||
for i := range keys {
|
||||
delete(r, keys[i])
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// OmitByValues returns same map type filtered by given values.
|
||||
// Play: https://go.dev/play/p/9UYZi-hrs8j
|
||||
func OmitByValues[K comparable, V comparable, Map ~map[K]V](in Map, values []V) Map {
|
||||
r := Map{}
|
||||
for k := range in {
|
||||
if !Contains(values, in[k]) {
|
||||
r[k] = in[k]
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Entries transforms a map into array of key/value pairs.
|
||||
// Play:
|
||||
func Entries[K comparable, V any](in map[K]V) []Entry[K, V] {
|
||||
entries := make([]Entry[K, V], 0, len(in))
|
||||
|
||||
for k := range in {
|
||||
entries = append(entries, Entry[K, V]{
|
||||
Key: k,
|
||||
Value: in[k],
|
||||
})
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
// ToPairs transforms a map into array of key/value pairs.
|
||||
// Alias of Entries().
|
||||
// Play: https://go.dev/play/p/3Dhgx46gawJ
|
||||
func ToPairs[K comparable, V any](in map[K]V) []Entry[K, V] {
|
||||
return Entries(in)
|
||||
}
|
||||
|
||||
// FromEntries transforms an array of key/value pairs into a map.
|
||||
// Play: https://go.dev/play/p/oIr5KHFGCEN
|
||||
func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
||||
out := make(map[K]V, len(entries))
|
||||
|
||||
for i := range entries {
|
||||
out[entries[i].Key] = entries[i].Value
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// FromPairs transforms an array of key/value pairs into a map.
|
||||
// Alias of FromEntries().
|
||||
// Play: https://go.dev/play/p/oIr5KHFGCEN
|
||||
func FromPairs[K comparable, V any](entries []Entry[K, V]) map[K]V {
|
||||
return FromEntries(entries)
|
||||
}
|
||||
|
||||
// Invert creates a map composed of the inverted keys and values. If map
|
||||
// contains duplicate values, subsequent values overwrite property assignments
|
||||
// of previous values.
|
||||
// Play: https://go.dev/play/p/rFQ4rak6iA1
|
||||
func Invert[K comparable, V comparable](in map[K]V) map[V]K {
|
||||
out := make(map[V]K, len(in))
|
||||
|
||||
for k := range in {
|
||||
out[in[k]] = k
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Assign merges multiple maps from left to right.
|
||||
// Play: https://go.dev/play/p/VhwfJOyxf5o
|
||||
func Assign[K comparable, V any, Map ~map[K]V](maps ...Map) Map {
|
||||
count := 0
|
||||
for i := range maps {
|
||||
count += len(maps[i])
|
||||
}
|
||||
|
||||
out := make(Map, count)
|
||||
for i := range maps {
|
||||
for k := range maps[i] {
|
||||
out[k] = maps[i][k]
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// ChunkEntries splits a map into an array of elements in groups of a length equal to its size. If the map cannot be split evenly,
|
||||
// the final chunk will contain the remaining elements.
|
||||
// Play: https://go.dev/play/p/X_YQL6mmoD-
|
||||
func ChunkEntries[K comparable, V any](m map[K]V, size int) []map[K]V {
|
||||
if size <= 0 {
|
||||
panic("The chunk size must be greater than 0")
|
||||
}
|
||||
|
||||
count := len(m)
|
||||
if count == 0 {
|
||||
return []map[K]V{}
|
||||
}
|
||||
|
||||
chunksNum := count / size
|
||||
if count%size != 0 {
|
||||
chunksNum += 1
|
||||
}
|
||||
|
||||
result := make([]map[K]V, 0, chunksNum)
|
||||
|
||||
for k, v := range m {
|
||||
if len(result) == 0 || len(result[len(result)-1]) == size {
|
||||
result = append(result, make(map[K]V, size))
|
||||
}
|
||||
|
||||
result[len(result)-1][k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// MapKeys manipulates a map keys and transforms it to a map of another type.
|
||||
// Play: https://go.dev/play/p/9_4WPIqOetJ
|
||||
func MapKeys[K comparable, V any, R comparable](in map[K]V, iteratee func(value V, key K) R) map[R]V {
|
||||
result := make(map[R]V, len(in))
|
||||
|
||||
for k := range in {
|
||||
result[iteratee(in[k], k)] = in[k]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// MapValues manipulates a map values and transforms it to a map of another type.
|
||||
// Play: https://go.dev/play/p/T_8xAfvcf0W
|
||||
func MapValues[K comparable, V any, R any](in map[K]V, iteratee func(value V, key K) R) map[K]R {
|
||||
result := make(map[K]R, len(in))
|
||||
|
||||
for k := range in {
|
||||
result[k] = iteratee(in[k], k)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// MapEntries manipulates a map entries and transforms it to a map of another type.
|
||||
// Play: https://go.dev/play/p/VuvNQzxKimT
|
||||
func MapEntries[K1 comparable, V1 any, K2 comparable, V2 any](in map[K1]V1, iteratee func(key K1, value V1) (K2, V2)) map[K2]V2 {
|
||||
result := make(map[K2]V2, len(in))
|
||||
|
||||
for k1 := range in {
|
||||
k2, v2 := iteratee(k1, in[k1])
|
||||
result[k2] = v2
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// MapToSlice transforms a map into a slice based on specific iteratee
|
||||
// Play: https://go.dev/play/p/ZuiCZpDt6LD
|
||||
func MapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(key K, value V) R) []R {
|
||||
result := make([]R, 0, len(in))
|
||||
|
||||
for k := range in {
|
||||
result = append(result, iteratee(k, in[k]))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FilterMapToSlice transforms a map into a slice based on specific iteratee.
|
||||
// The iteratee returns a value and a boolean. If the boolean is true, the value is added to the result slice.
|
||||
// If the boolean is false, the value is not added to the result slice.
|
||||
// The order of the keys in the input map is not specified and the order of the keys in the output slice is not guaranteed.
|
||||
func FilterMapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(key K, value V) (R, bool)) []R {
|
||||
result := make([]R, 0, len(in))
|
||||
|
||||
for k := range in {
|
||||
if v, ok := iteratee(k, in[k]); ok {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
142
vendor/github.com/samber/lo/math.go
generated
vendored
Normal file
142
vendor/github.com/samber/lo/math.go
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"github.com/samber/lo/internal/constraints"
|
||||
)
|
||||
|
||||
// Range creates an array of numbers (positive and/or negative) with given length.
|
||||
// Play: https://go.dev/play/p/0r6VimXAi9H
|
||||
func Range(elementNum int) []int {
|
||||
length := If(elementNum < 0, -elementNum).Else(elementNum)
|
||||
result := make([]int, length)
|
||||
step := If(elementNum < 0, -1).Else(1)
|
||||
for i, j := 0, 0; i < length; i, j = i+1, j+step {
|
||||
result[i] = j
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// RangeFrom creates an array of numbers from start with specified length.
|
||||
// Play: https://go.dev/play/p/0r6VimXAi9H
|
||||
func RangeFrom[T constraints.Integer | constraints.Float](start T, elementNum int) []T {
|
||||
length := If(elementNum < 0, -elementNum).Else(elementNum)
|
||||
result := make([]T, length)
|
||||
step := If(elementNum < 0, -1).Else(1)
|
||||
for i, j := 0, start; i < length; i, j = i+1, j+T(step) {
|
||||
result[i] = j
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// RangeWithSteps creates an array of numbers (positive and/or negative) progressing from start up to, but not including end.
|
||||
// step set to zero will return empty array.
|
||||
// Play: https://go.dev/play/p/0r6VimXAi9H
|
||||
func RangeWithSteps[T constraints.Integer | constraints.Float](start, end, step T) []T {
|
||||
result := []T{}
|
||||
if start == end || step == 0 {
|
||||
return result
|
||||
}
|
||||
if start < end {
|
||||
if step < 0 {
|
||||
return result
|
||||
}
|
||||
for i := start; i < end; i += step {
|
||||
result = append(result, i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
if step > 0 {
|
||||
return result
|
||||
}
|
||||
for i := start; i > end; i += step {
|
||||
result = append(result, i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Clamp clamps number within the inclusive lower and upper bounds.
|
||||
// Play: https://go.dev/play/p/RU4lJNC2hlI
|
||||
func Clamp[T constraints.Ordered](value T, min T, max T) T {
|
||||
if value < min {
|
||||
return min
|
||||
} else if value > max {
|
||||
return max
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Sum sums the values in a collection. If collection is empty 0 is returned.
|
||||
// Play: https://go.dev/play/p/upfeJVqs4Bt
|
||||
func Sum[T constraints.Float | constraints.Integer | constraints.Complex](collection []T) T {
|
||||
var sum T = 0
|
||||
for i := range collection {
|
||||
sum += collection[i]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// SumBy summarizes the values in a collection using the given return value from the iteration function. If collection is empty 0 is returned.
|
||||
// Play: https://go.dev/play/p/Dz_a_7jN_ca
|
||||
func SumBy[T any, R constraints.Float | constraints.Integer | constraints.Complex](collection []T, iteratee func(item T) R) R {
|
||||
var sum R = 0
|
||||
for i := range collection {
|
||||
sum = sum + iteratee(collection[i])
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Product gets the product of the values in a collection. If collection is empty 0 is returned.
|
||||
// Play: https://go.dev/play/p/2_kjM_smtAH
|
||||
func Product[T constraints.Float | constraints.Integer | constraints.Complex](collection []T) T {
|
||||
if collection == nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(collection) == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
var product T = 1
|
||||
for i := range collection {
|
||||
product *= collection[i]
|
||||
}
|
||||
return product
|
||||
}
|
||||
|
||||
// ProductBy summarizes the values in a collection using the given return value from the iteration function. If collection is empty 0 is returned.
|
||||
// Play: https://go.dev/play/p/wadzrWr9Aer
|
||||
func ProductBy[T any, R constraints.Float | constraints.Integer | constraints.Complex](collection []T, iteratee func(item T) R) R {
|
||||
if collection == nil {
|
||||
return 1
|
||||
}
|
||||
|
||||
if len(collection) == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
var product R = 1
|
||||
for i := range collection {
|
||||
product = product * iteratee(collection[i])
|
||||
}
|
||||
return product
|
||||
}
|
||||
|
||||
// Mean calculates the mean of a collection of numbers.
|
||||
func Mean[T constraints.Float | constraints.Integer](collection []T) T {
|
||||
var length = T(len(collection))
|
||||
if length == 0 {
|
||||
return 0
|
||||
}
|
||||
var sum = Sum(collection)
|
||||
return sum / length
|
||||
}
|
||||
|
||||
// MeanBy calculates the mean of a collection of numbers using the given return value from the iteration function.
|
||||
func MeanBy[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(item T) R) R {
|
||||
var length = R(len(collection))
|
||||
if length == 0 {
|
||||
return 0
|
||||
}
|
||||
var sum = SumBy(collection, iteratee)
|
||||
return sum / length
|
||||
}
|
||||
71
vendor/github.com/samber/lo/mutable/slice.go
generated
vendored
Normal file
71
vendor/github.com/samber/lo/mutable/slice.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package mutable
|
||||
|
||||
import "github.com/samber/lo/internal/rand"
|
||||
|
||||
// Filter is a generic function that modifies the input slice in-place to contain only the elements
|
||||
// that satisfy the provided predicate function. The predicate function takes an element of the slice and its index,
|
||||
// and should return true for elements that should be kept and false for elements that should be removed.
|
||||
// The function returns the modified slice, which may be shorter than the original if some elements were removed.
|
||||
// Note that the order of elements in the original slice is preserved in the output.
|
||||
func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice {
|
||||
j := 0
|
||||
for _, item := range collection {
|
||||
if predicate(item) {
|
||||
collection[j] = item
|
||||
j++
|
||||
}
|
||||
}
|
||||
return collection[:j]
|
||||
}
|
||||
|
||||
// FilterI is a generic function that modifies the input slice in-place to contain only the elements
|
||||
// that satisfy the provided predicate function. The predicate function takes an element of the slice and its index,
|
||||
// and should return true for elements that should be kept and false for elements that should be removed.
|
||||
// The function returns the modified slice, which may be shorter than the original if some elements were removed.
|
||||
// Note that the order of elements in the original slice is preserved in the output.
|
||||
func FilterI[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
|
||||
j := 0
|
||||
for i, item := range collection {
|
||||
if predicate(item, i) {
|
||||
collection[j] = item
|
||||
j++
|
||||
}
|
||||
}
|
||||
return collection[:j]
|
||||
}
|
||||
|
||||
// Map is a generic function that modifies the input slice in-place to contain the result of applying the provided
|
||||
// function to each element of the slice. The function returns the modified slice, which has the same length as the original.
|
||||
func Map[T any, Slice ~[]T](collection Slice, fn func(item T) T) {
|
||||
for i := range collection {
|
||||
collection[i] = fn(collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
// MapI is a generic function that modifies the input slice in-place to contain the result of applying the provided
|
||||
// function to each element of the slice. The function returns the modified slice, which has the same length as the original.
|
||||
func MapI[T any, Slice ~[]T](collection Slice, fn func(item T, index int) T) {
|
||||
for i := range collection {
|
||||
collection[i] = fn(collection[i], i)
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm.
|
||||
// Play: https://go.dev/play/p/2xb3WdLjeSJ
|
||||
func Shuffle[T any, Slice ~[]T](collection Slice) {
|
||||
rand.Shuffle(len(collection), func(i, j int) {
|
||||
collection[i], collection[j] = collection[j], collection[i]
|
||||
})
|
||||
}
|
||||
|
||||
// Reverse reverses array so that the first element becomes the last, the second element becomes the second to last, and so on.
|
||||
// Play: https://go.dev/play/p/O-M5pmCRgzV
|
||||
func Reverse[T any, Slice ~[]T](collection Slice) {
|
||||
length := len(collection)
|
||||
half := length / 2
|
||||
|
||||
for i := 0; i < half; i = i + 1 {
|
||||
j := length - 1 - i
|
||||
collection[i], collection[j] = collection[j], collection[i]
|
||||
}
|
||||
}
|
||||
375
vendor/github.com/samber/lo/retry.go
generated
vendored
Normal file
375
vendor/github.com/samber/lo/retry.go
generated
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type debounce struct {
|
||||
after time.Duration
|
||||
mu *sync.Mutex
|
||||
timer *time.Timer
|
||||
done bool
|
||||
callbacks []func()
|
||||
}
|
||||
|
||||
func (d *debounce) reset() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.done {
|
||||
return
|
||||
}
|
||||
|
||||
if d.timer != nil {
|
||||
d.timer.Stop()
|
||||
}
|
||||
|
||||
d.timer = time.AfterFunc(d.after, func() {
|
||||
for i := range d.callbacks {
|
||||
d.callbacks[i]()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (d *debounce) cancel() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.timer != nil {
|
||||
d.timer.Stop()
|
||||
d.timer = nil
|
||||
}
|
||||
|
||||
d.done = true
|
||||
}
|
||||
|
||||
// NewDebounce creates a debounced instance that delays invoking functions given until after wait milliseconds have elapsed.
|
||||
// Play: https://go.dev/play/p/mz32VMK2nqe
|
||||
func NewDebounce(duration time.Duration, f ...func()) (func(), func()) {
|
||||
d := &debounce{
|
||||
after: duration,
|
||||
mu: new(sync.Mutex),
|
||||
timer: nil,
|
||||
done: false,
|
||||
callbacks: f,
|
||||
}
|
||||
|
||||
return func() {
|
||||
d.reset()
|
||||
}, d.cancel
|
||||
}
|
||||
|
||||
type debounceByItem struct {
|
||||
mu *sync.Mutex
|
||||
timer *time.Timer
|
||||
count int
|
||||
}
|
||||
|
||||
type debounceBy[T comparable] struct {
|
||||
after time.Duration
|
||||
mu *sync.Mutex
|
||||
items map[T]*debounceByItem
|
||||
callbacks []func(key T, count int)
|
||||
}
|
||||
|
||||
func (d *debounceBy[T]) reset(key T) {
|
||||
d.mu.Lock()
|
||||
if _, ok := d.items[key]; !ok {
|
||||
d.items[key] = &debounceByItem{
|
||||
mu: new(sync.Mutex),
|
||||
timer: nil,
|
||||
}
|
||||
}
|
||||
|
||||
item := d.items[key]
|
||||
|
||||
d.mu.Unlock()
|
||||
|
||||
item.mu.Lock()
|
||||
defer item.mu.Unlock()
|
||||
|
||||
item.count++
|
||||
|
||||
if item.timer != nil {
|
||||
item.timer.Stop()
|
||||
}
|
||||
|
||||
item.timer = time.AfterFunc(d.after, func() {
|
||||
item.mu.Lock()
|
||||
count := item.count
|
||||
item.count = 0
|
||||
item.mu.Unlock()
|
||||
|
||||
for i := range d.callbacks {
|
||||
d.callbacks[i](key, count)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (d *debounceBy[T]) cancel(key T) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if item, ok := d.items[key]; ok {
|
||||
item.mu.Lock()
|
||||
|
||||
if item.timer != nil {
|
||||
item.timer.Stop()
|
||||
item.timer = nil
|
||||
}
|
||||
|
||||
item.mu.Unlock()
|
||||
|
||||
delete(d.items, key)
|
||||
}
|
||||
}
|
||||
|
||||
// NewDebounceBy creates a debounced instance for each distinct key, that delays invoking functions given until after wait milliseconds have elapsed.
|
||||
// Play: https://go.dev/play/p/d3Vpt6pxhY8
|
||||
func NewDebounceBy[T comparable](duration time.Duration, f ...func(key T, count int)) (func(key T), func(key T)) {
|
||||
d := &debounceBy[T]{
|
||||
after: duration,
|
||||
mu: new(sync.Mutex),
|
||||
items: map[T]*debounceByItem{},
|
||||
callbacks: f,
|
||||
}
|
||||
|
||||
return func(key T) {
|
||||
d.reset(key)
|
||||
}, d.cancel
|
||||
}
|
||||
|
||||
// Attempt invokes a function N times until it returns valid output. Returns either the caught error or nil.
|
||||
// When the first argument is less than `1`, the function runs until a successful response is returned.
|
||||
// Play: https://go.dev/play/p/3ggJZ2ZKcMj
|
||||
func Attempt(maxIteration int, f func(index int) error) (int, error) {
|
||||
var err error
|
||||
|
||||
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
|
||||
// for retries >= 0 {
|
||||
err = f(i)
|
||||
if err == nil {
|
||||
return i + 1, nil
|
||||
}
|
||||
}
|
||||
|
||||
return maxIteration, err
|
||||
}
|
||||
|
||||
// AttemptWithDelay invokes a function N times until it returns valid output,
|
||||
// with a pause between each call. Returns either the caught error or nil.
|
||||
// When the first argument is less than `1`, the function runs until a successful
|
||||
// response is returned.
|
||||
// Play: https://go.dev/play/p/tVs6CygC7m1
|
||||
func AttemptWithDelay(maxIteration int, delay time.Duration, f func(index int, duration time.Duration) error) (int, time.Duration, error) {
|
||||
var err error
|
||||
|
||||
start := time.Now()
|
||||
|
||||
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
|
||||
err = f(i, time.Since(start))
|
||||
if err == nil {
|
||||
return i + 1, time.Since(start), nil
|
||||
}
|
||||
|
||||
if maxIteration <= 0 || i+1 < maxIteration {
|
||||
time.Sleep(delay)
|
||||
}
|
||||
}
|
||||
|
||||
return maxIteration, time.Since(start), err
|
||||
}
|
||||
|
||||
// AttemptWhile invokes a function N times until it returns valid output.
|
||||
// Returns either the caught error or nil, along with a bool value to determine
|
||||
// whether the function should be invoked again. It will terminate the invoke
|
||||
// immediately if the second return value is false. When the first
|
||||
// argument is less than `1`, the function runs until a successful response is
|
||||
// returned.
|
||||
func AttemptWhile(maxIteration int, f func(int) (error, bool)) (int, error) {
|
||||
var err error
|
||||
var shouldContinueInvoke bool
|
||||
|
||||
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
|
||||
// for retries >= 0 {
|
||||
err, shouldContinueInvoke = f(i)
|
||||
if !shouldContinueInvoke { // if shouldContinueInvoke is false, then return immediately
|
||||
return i + 1, err
|
||||
}
|
||||
if err == nil {
|
||||
return i + 1, nil
|
||||
}
|
||||
}
|
||||
|
||||
return maxIteration, err
|
||||
}
|
||||
|
||||
// AttemptWhileWithDelay invokes a function N times until it returns valid output,
|
||||
// with a pause between each call. Returns either the caught error or nil, along
|
||||
// with a bool value to determine whether the function should be invoked again.
|
||||
// It will terminate the invoke immediately if the second return value is false.
|
||||
// When the first argument is less than `1`, the function runs until a successful
|
||||
// response is returned.
|
||||
func AttemptWhileWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) (error, bool)) (int, time.Duration, error) {
|
||||
var err error
|
||||
var shouldContinueInvoke bool
|
||||
|
||||
start := time.Now()
|
||||
|
||||
for i := 0; maxIteration <= 0 || i < maxIteration; i++ {
|
||||
err, shouldContinueInvoke = f(i, time.Since(start))
|
||||
if !shouldContinueInvoke { // if shouldContinueInvoke is false, then return immediately
|
||||
return i + 1, time.Since(start), err
|
||||
}
|
||||
if err == nil {
|
||||
return i + 1, time.Since(start), nil
|
||||
}
|
||||
|
||||
if maxIteration <= 0 || i+1 < maxIteration {
|
||||
time.Sleep(delay)
|
||||
}
|
||||
}
|
||||
|
||||
return maxIteration, time.Since(start), err
|
||||
}
|
||||
|
||||
type transactionStep[T any] struct {
|
||||
exec func(T) (T, error)
|
||||
onRollback func(T) T
|
||||
}
|
||||
|
||||
// NewTransaction instantiate a new transaction.
|
||||
func NewTransaction[T any]() *Transaction[T] {
|
||||
return &Transaction[T]{
|
||||
steps: []transactionStep[T]{},
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction implements a Saga pattern
|
||||
type Transaction[T any] struct {
|
||||
steps []transactionStep[T]
|
||||
}
|
||||
|
||||
// Then adds a step to the chain of callbacks. It returns the same Transaction.
|
||||
func (t *Transaction[T]) Then(exec func(T) (T, error), onRollback func(T) T) *Transaction[T] {
|
||||
t.steps = append(t.steps, transactionStep[T]{
|
||||
exec: exec,
|
||||
onRollback: onRollback,
|
||||
})
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// Process runs the Transaction steps and rollbacks in case of errors.
|
||||
func (t *Transaction[T]) Process(state T) (T, error) {
|
||||
var i int
|
||||
var err error
|
||||
|
||||
for i < len(t.steps) {
|
||||
state, err = t.steps[i].exec(state)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
for i > 0 {
|
||||
i--
|
||||
state = t.steps[i].onRollback(state)
|
||||
}
|
||||
|
||||
return state, err
|
||||
}
|
||||
|
||||
// @TODO: single mutex per key ?
|
||||
type throttleBy[T comparable] struct {
|
||||
mu *sync.Mutex
|
||||
timer *time.Timer
|
||||
interval time.Duration
|
||||
callbacks []func(key T)
|
||||
countLimit int
|
||||
count map[T]int
|
||||
}
|
||||
|
||||
func (th *throttleBy[T]) throttledFunc(key T) {
|
||||
th.mu.Lock()
|
||||
defer th.mu.Unlock()
|
||||
|
||||
if _, ok := th.count[key]; !ok {
|
||||
th.count[key] = 0
|
||||
}
|
||||
|
||||
if th.count[key] < th.countLimit {
|
||||
th.count[key]++
|
||||
|
||||
for _, f := range th.callbacks {
|
||||
f(key)
|
||||
}
|
||||
|
||||
}
|
||||
if th.timer == nil {
|
||||
th.timer = time.AfterFunc(th.interval, func() {
|
||||
th.reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (th *throttleBy[T]) reset() {
|
||||
th.mu.Lock()
|
||||
defer th.mu.Unlock()
|
||||
|
||||
if th.timer != nil {
|
||||
th.timer.Stop()
|
||||
}
|
||||
|
||||
th.count = map[T]int{}
|
||||
th.timer = nil
|
||||
}
|
||||
|
||||
// NewThrottle creates a throttled instance that invokes given functions only once in every interval.
|
||||
// This returns 2 functions, First one is throttled function and Second one is a function to reset interval
|
||||
func NewThrottle(interval time.Duration, f ...func()) (throttle func(), reset func()) {
|
||||
return NewThrottleWithCount(interval, 1, f...)
|
||||
}
|
||||
|
||||
// NewThrottleWithCount is NewThrottle with count limit, throttled function will be invoked count times in every interval.
|
||||
func NewThrottleWithCount(interval time.Duration, count int, f ...func()) (throttle func(), reset func()) {
|
||||
callbacks := Map(f, func(item func(), _ int) func(struct{}) {
|
||||
return func(struct{}) {
|
||||
item()
|
||||
}
|
||||
})
|
||||
|
||||
throttleFn, reset := NewThrottleByWithCount[struct{}](interval, count, callbacks...)
|
||||
return func() {
|
||||
throttleFn(struct{}{})
|
||||
}, reset
|
||||
}
|
||||
|
||||
// NewThrottleBy creates a throttled instance that invokes given functions only once in every interval.
|
||||
// This returns 2 functions, First one is throttled function and Second one is a function to reset interval
|
||||
func NewThrottleBy[T comparable](interval time.Duration, f ...func(key T)) (throttle func(key T), reset func()) {
|
||||
return NewThrottleByWithCount[T](interval, 1, f...)
|
||||
}
|
||||
|
||||
// NewThrottleByWithCount is NewThrottleBy with count limit, throttled function will be invoked count times in every interval.
|
||||
func NewThrottleByWithCount[T comparable](interval time.Duration, count int, f ...func(key T)) (throttle func(key T), reset func()) {
|
||||
if count <= 0 {
|
||||
count = 1
|
||||
}
|
||||
|
||||
th := &throttleBy[T]{
|
||||
mu: new(sync.Mutex),
|
||||
interval: interval,
|
||||
callbacks: f,
|
||||
countLimit: count,
|
||||
count: map[T]int{},
|
||||
}
|
||||
return th.throttledFunc, th.reset
|
||||
}
|
||||
745
vendor/github.com/samber/lo/slice.go
generated
vendored
Normal file
745
vendor/github.com/samber/lo/slice.go
generated
vendored
Normal file
@@ -0,0 +1,745 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/samber/lo/internal/constraints"
|
||||
"github.com/samber/lo/mutable"
|
||||
)
|
||||
|
||||
// Filter iterates over elements of collection, returning an array of all elements predicate returns truthy for.
|
||||
// Play: https://go.dev/play/p/Apjg3WeSi7K
|
||||
func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
|
||||
result := make(Slice, 0, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
if predicate(collection[i], i) {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Map manipulates a slice and transforms it to a slice of another type.
|
||||
// Play: https://go.dev/play/p/OkPcYAhBo0D
|
||||
func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R {
|
||||
result := make([]R, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
result[i] = iteratee(collection[i], i)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqMap manipulates a slice and transforms it to a slice of another type with unique values.
|
||||
func UniqMap[T any, R comparable](collection []T, iteratee func(item T, index int) R) []R {
|
||||
result := make([]R, 0, len(collection))
|
||||
seen := make(map[R]struct{}, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
r := iteratee(collection[i], i)
|
||||
if _, ok := seen[r]; !ok {
|
||||
result = append(result, r)
|
||||
seen[r] = struct{}{}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FilterMap returns a slice which obtained after both filtering and mapping using the given callback function.
|
||||
// The callback function should return two values:
|
||||
// - the result of the mapping operation and
|
||||
// - whether the result element should be included or not.
|
||||
//
|
||||
// Play: https://go.dev/play/p/-AuYXfy7opz
|
||||
func FilterMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R {
|
||||
result := make([]R, 0, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
if r, ok := callback(collection[i], i); ok {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
|
||||
// The transform function can either return a slice or a `nil`, and in the `nil` case
|
||||
// no value is added to the final slice.
|
||||
// Play: https://go.dev/play/p/YSoYmQTA8-U
|
||||
func FlatMap[T any, R any](collection []T, iteratee func(item T, index int) []R) []R {
|
||||
result := make([]R, 0, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
result = append(result, iteratee(collection[i], i)...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Reduce reduces collection to a value which is the accumulated result of running each element in collection
|
||||
// through accumulator, where each successive invocation is supplied the return value of the previous.
|
||||
// Play: https://go.dev/play/p/R4UHXZNaaUG
|
||||
func Reduce[T any, R any](collection []T, accumulator func(agg R, item T, index int) R, initial R) R {
|
||||
for i := range collection {
|
||||
initial = accumulator(initial, collection[i], i)
|
||||
}
|
||||
|
||||
return initial
|
||||
}
|
||||
|
||||
// ReduceRight helper is like Reduce except that it iterates over elements of collection from right to left.
|
||||
// Play: https://go.dev/play/p/Fq3W70l7wXF
|
||||
func ReduceRight[T any, R any](collection []T, accumulator func(agg R, item T, index int) R, initial R) R {
|
||||
for i := len(collection) - 1; i >= 0; i-- {
|
||||
initial = accumulator(initial, collection[i], i)
|
||||
}
|
||||
|
||||
return initial
|
||||
}
|
||||
|
||||
// ForEach iterates over elements of collection and invokes iteratee for each element.
|
||||
// Play: https://go.dev/play/p/oofyiUPRf8t
|
||||
func ForEach[T any](collection []T, iteratee func(item T, index int)) {
|
||||
for i := range collection {
|
||||
iteratee(collection[i], i)
|
||||
}
|
||||
}
|
||||
|
||||
// ForEachWhile iterates over elements of collection and invokes iteratee for each element
|
||||
// collection return value decide to continue or break, like do while().
|
||||
// Play: https://go.dev/play/p/QnLGt35tnow
|
||||
func ForEachWhile[T any](collection []T, iteratee func(item T, index int) (goon bool)) {
|
||||
for i := range collection {
|
||||
if !iteratee(collection[i], i) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Times invokes the iteratee n times, returning an array of the results of each invocation.
|
||||
// The iteratee is invoked with index as argument.
|
||||
// Play: https://go.dev/play/p/vgQj3Glr6lT
|
||||
func Times[T any](count int, iteratee func(index int) T) []T {
|
||||
result := make([]T, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
result[i] = iteratee(i)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Uniq returns a duplicate-free version of an array, in which only the first occurrence of each element is kept.
|
||||
// The order of result values is determined by the order they occur in the array.
|
||||
// Play: https://go.dev/play/p/DTzbeXZ6iEN
|
||||
func Uniq[T comparable, Slice ~[]T](collection Slice) Slice {
|
||||
result := make(Slice, 0, len(collection))
|
||||
seen := make(map[T]struct{}, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
if _, ok := seen[collection[i]]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
seen[collection[i]] = struct{}{}
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// UniqBy returns a duplicate-free version of an array, in which only the first occurrence of each element is kept.
|
||||
// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is
|
||||
// invoked for each element in array to generate the criterion by which uniqueness is computed.
|
||||
// Play: https://go.dev/play/p/g42Z3QSb53u
|
||||
func UniqBy[T any, U comparable, Slice ~[]T](collection Slice, iteratee func(item T) U) Slice {
|
||||
result := make(Slice, 0, len(collection))
|
||||
seen := make(map[U]struct{}, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
if _, ok := seen[key]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
seen[key] = struct{}{}
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GroupBy returns an object composed of keys generated from the results of running each element of collection through iteratee.
|
||||
// Play: https://go.dev/play/p/XnQBd_v6brd
|
||||
func GroupBy[T any, U comparable, Slice ~[]T](collection Slice, iteratee func(item T) U) map[U]Slice {
|
||||
result := map[U]Slice{}
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
result[key] = append(result[key], collection[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GroupByMap returns an object composed of keys generated from the results of running each element of collection through iteratee.
|
||||
func GroupByMap[T any, K comparable, V any](collection []T, iteratee func(item T) (K, V)) map[K][]V {
|
||||
result := map[K][]V{}
|
||||
|
||||
for i := range collection {
|
||||
k, v := iteratee(collection[i])
|
||||
|
||||
result[k] = append(result[k], v)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Chunk returns an array of elements split into groups the length of size. If array can't be split evenly,
|
||||
// the final chunk will be the remaining elements.
|
||||
// Play: https://go.dev/play/p/EeKl0AuTehH
|
||||
func Chunk[T any, Slice ~[]T](collection Slice, size int) []Slice {
|
||||
if size <= 0 {
|
||||
panic("Second parameter must be greater than 0")
|
||||
}
|
||||
|
||||
chunksNum := len(collection) / size
|
||||
if len(collection)%size != 0 {
|
||||
chunksNum += 1
|
||||
}
|
||||
|
||||
result := make([]Slice, 0, chunksNum)
|
||||
|
||||
for i := 0; i < chunksNum; i++ {
|
||||
last := (i + 1) * size
|
||||
if last > len(collection) {
|
||||
last = len(collection)
|
||||
}
|
||||
result = append(result, collection[i*size:last:last])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// PartitionBy returns an array of elements split into groups. The order of grouped values is
|
||||
// determined by the order they occur in collection. The grouping is generated from the results
|
||||
// of running each element of collection through iteratee.
|
||||
// Play: https://go.dev/play/p/NfQ_nGjkgXW
|
||||
func PartitionBy[T any, K comparable, Slice ~[]T](collection Slice, iteratee func(item T) K) []Slice {
|
||||
result := []Slice{}
|
||||
seen := map[K]int{}
|
||||
|
||||
for i := range collection {
|
||||
key := iteratee(collection[i])
|
||||
|
||||
resultIndex, ok := seen[key]
|
||||
if !ok {
|
||||
resultIndex = len(result)
|
||||
seen[key] = resultIndex
|
||||
result = append(result, Slice{})
|
||||
}
|
||||
|
||||
result[resultIndex] = append(result[resultIndex], collection[i])
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
// unordered:
|
||||
// groups := GroupBy[T, K](collection, iteratee)
|
||||
// return Values[K, []T](groups)
|
||||
}
|
||||
|
||||
// Flatten returns an array a single level deep.
|
||||
// Play: https://go.dev/play/p/rbp9ORaMpjw
|
||||
func Flatten[T any, Slice ~[]T](collection []Slice) Slice {
|
||||
totalLen := 0
|
||||
for i := range collection {
|
||||
totalLen += len(collection[i])
|
||||
}
|
||||
|
||||
result := make(Slice, 0, totalLen)
|
||||
for i := range collection {
|
||||
result = append(result, collection[i]...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Interleave round-robin alternating input slices and sequentially appending value at index into result
|
||||
// Play: https://go.dev/play/p/-RJkTLQEDVt
|
||||
func Interleave[T any, Slice ~[]T](collections ...Slice) Slice {
|
||||
if len(collections) == 0 {
|
||||
return Slice{}
|
||||
}
|
||||
|
||||
maxSize := 0
|
||||
totalSize := 0
|
||||
for i := range collections {
|
||||
size := len(collections[i])
|
||||
totalSize += size
|
||||
if size > maxSize {
|
||||
maxSize = size
|
||||
}
|
||||
}
|
||||
|
||||
if maxSize == 0 {
|
||||
return Slice{}
|
||||
}
|
||||
|
||||
result := make(Slice, totalSize)
|
||||
|
||||
resultIdx := 0
|
||||
for i := 0; i < maxSize; i++ {
|
||||
for j := range collections {
|
||||
if len(collections[j])-1 < i {
|
||||
continue
|
||||
}
|
||||
|
||||
result[resultIdx] = collections[j][i]
|
||||
resultIdx++
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Shuffle returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm.
|
||||
// Play: https://go.dev/play/p/ZTGG7OUCdnp
|
||||
//
|
||||
// Deprecated: use mutable.Shuffle() instead.
|
||||
func Shuffle[T any, Slice ~[]T](collection Slice) Slice {
|
||||
mutable.Shuffle(collection)
|
||||
return collection
|
||||
}
|
||||
|
||||
// Reverse reverses array so that the first element becomes the last, the second element becomes the second to last, and so on.
|
||||
// Play: https://go.dev/play/p/iv2e9jslfBM
|
||||
//
|
||||
// Deprecated: use mutable.Reverse() instead.
|
||||
func Reverse[T any, Slice ~[]T](collection Slice) Slice {
|
||||
mutable.Reverse(collection)
|
||||
return collection
|
||||
}
|
||||
|
||||
// Fill fills elements of array with `initial` value.
|
||||
// Play: https://go.dev/play/p/VwR34GzqEub
|
||||
func Fill[T Clonable[T], Slice ~[]T](collection Slice, initial T) Slice {
|
||||
result := make(Slice, 0, len(collection))
|
||||
|
||||
for range collection {
|
||||
result = append(result, initial.Clone())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Repeat builds a slice with N copies of initial value.
|
||||
// Play: https://go.dev/play/p/g3uHXbmc3b6
|
||||
func Repeat[T Clonable[T]](count int, initial T) []T {
|
||||
result := make([]T, 0, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
result = append(result, initial.Clone())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// RepeatBy builds a slice with values returned by N calls of callback.
|
||||
// Play: https://go.dev/play/p/ozZLCtX_hNU
|
||||
func RepeatBy[T any](count int, predicate func(index int) T) []T {
|
||||
result := make([]T, 0, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
result = append(result, predicate(i))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// KeyBy transforms a slice or an array of structs to a map based on a pivot callback.
|
||||
// Play: https://go.dev/play/p/mdaClUAT-zZ
|
||||
func KeyBy[K comparable, V any](collection []V, iteratee func(item V) K) map[K]V {
|
||||
result := make(map[K]V, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
k := iteratee(collection[i])
|
||||
result[k] = collection[i]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Associate returns a map containing key-value pairs provided by transform function applied to elements of the given slice.
|
||||
// If any of two pairs would have the same key the last one gets added to the map.
|
||||
// The order of keys in returned map is not specified and is not guaranteed to be the same from the original array.
|
||||
// Play: https://go.dev/play/p/WHa2CfMO3Lr
|
||||
func Associate[T any, K comparable, V any](collection []T, transform func(item T) (K, V)) map[K]V {
|
||||
result := make(map[K]V, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
k, v := transform(collection[i])
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// SliceToMap returns a map containing key-value pairs provided by transform function applied to elements of the given slice.
|
||||
// If any of two pairs would have the same key the last one gets added to the map.
|
||||
// The order of keys in returned map is not specified and is not guaranteed to be the same from the original array.
|
||||
// Alias of Associate().
|
||||
// Play: https://go.dev/play/p/WHa2CfMO3Lr
|
||||
func SliceToMap[T any, K comparable, V any](collection []T, transform func(item T) (K, V)) map[K]V {
|
||||
return Associate(collection, transform)
|
||||
}
|
||||
|
||||
// FilterSliceToMap returns a map containing key-value pairs provided by transform function applied to elements of the given slice.
|
||||
// If any of two pairs would have the same key the last one gets added to the map.
|
||||
// The order of keys in returned map is not specified and is not guaranteed to be the same from the original array.
|
||||
// The third return value of the transform function is a boolean that indicates whether the key-value pair should be included in the map.
|
||||
func FilterSliceToMap[T any, K comparable, V any](collection []T, transform func(item T) (K, V, bool)) map[K]V {
|
||||
result := make(map[K]V, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
k, v, ok := transform(collection[i])
|
||||
if ok {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Keyify returns a map with each unique element of the slice as a key.
|
||||
func Keyify[T comparable, Slice ~[]T](collection Slice) map[T]struct{} {
|
||||
result := make(map[T]struct{}, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
result[collection[i]] = struct{}{}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Drop drops n elements from the beginning of a slice or array.
|
||||
// Play: https://go.dev/play/p/JswS7vXRJP2
|
||||
func Drop[T any, Slice ~[]T](collection Slice, n int) Slice {
|
||||
if len(collection) <= n {
|
||||
return make(Slice, 0)
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-n)
|
||||
|
||||
return append(result, collection[n:]...)
|
||||
}
|
||||
|
||||
// DropRight drops n elements from the end of a slice or array.
|
||||
// Play: https://go.dev/play/p/GG0nXkSJJa3
|
||||
func DropRight[T any, Slice ~[]T](collection Slice, n int) Slice {
|
||||
if len(collection) <= n {
|
||||
return Slice{}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-n)
|
||||
return append(result, collection[:len(collection)-n]...)
|
||||
}
|
||||
|
||||
// DropWhile drops elements from the beginning of a slice or array while the predicate returns true.
|
||||
// Play: https://go.dev/play/p/7gBPYw2IK16
|
||||
func DropWhile[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice {
|
||||
i := 0
|
||||
for ; i < len(collection); i++ {
|
||||
if !predicate(collection[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, len(collection)-i)
|
||||
return append(result, collection[i:]...)
|
||||
}
|
||||
|
||||
// DropRightWhile drops elements from the end of a slice or array while the predicate returns true.
|
||||
// Play: https://go.dev/play/p/3-n71oEC0Hz
|
||||
func DropRightWhile[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice {
|
||||
i := len(collection) - 1
|
||||
for ; i >= 0; i-- {
|
||||
if !predicate(collection[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
result := make(Slice, 0, i+1)
|
||||
return append(result, collection[:i+1]...)
|
||||
}
|
||||
|
||||
// DropByIndex drops elements from a slice or array by the index.
|
||||
// A negative index will drop elements from the end of the slice.
|
||||
// Play: https://go.dev/play/p/bPIH4npZRxS
|
||||
func DropByIndex[T any](collection []T, indexes ...int) []T {
|
||||
initialSize := len(collection)
|
||||
if initialSize == 0 {
|
||||
return make([]T, 0)
|
||||
}
|
||||
|
||||
for i := range indexes {
|
||||
if indexes[i] < 0 {
|
||||
indexes[i] = initialSize + indexes[i]
|
||||
}
|
||||
}
|
||||
|
||||
indexes = Uniq(indexes)
|
||||
sort.Ints(indexes)
|
||||
|
||||
result := make([]T, 0, initialSize)
|
||||
result = append(result, collection...)
|
||||
|
||||
for i := range indexes {
|
||||
if indexes[i]-i < 0 || indexes[i]-i >= initialSize-i {
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result[:indexes[i]-i], result[indexes[i]-i+1:]...)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Reject is the opposite of Filter, this method returns the elements of collection that predicate does not return truthy for.
|
||||
// Play: https://go.dev/play/p/YkLMODy1WEL
|
||||
func Reject[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
|
||||
result := Slice{}
|
||||
|
||||
for i := range collection {
|
||||
if !predicate(collection[i], i) {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// RejectMap is the opposite of FilterMap, this method returns a slice which obtained after both filtering and mapping using the given callback function.
|
||||
// The callback function should return two values:
|
||||
// - the result of the mapping operation and
|
||||
// - whether the result element should be included or not.
|
||||
func RejectMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R {
|
||||
result := []R{}
|
||||
|
||||
for i := range collection {
|
||||
if r, ok := callback(collection[i], i); !ok {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FilterReject mixes Filter and Reject, this method returns two slices, one for the elements of collection that
|
||||
// predicate returns truthy for and one for the elements that predicate does not return truthy for.
|
||||
func FilterReject[T any, Slice ~[]T](collection Slice, predicate func(T, int) bool) (kept Slice, rejected Slice) {
|
||||
kept = make(Slice, 0, len(collection))
|
||||
rejected = make(Slice, 0, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
if predicate(collection[i], i) {
|
||||
kept = append(kept, collection[i])
|
||||
} else {
|
||||
rejected = append(rejected, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return kept, rejected
|
||||
}
|
||||
|
||||
// Count counts the number of elements in the collection that compare equal to value.
|
||||
// Play: https://go.dev/play/p/Y3FlK54yveC
|
||||
func Count[T comparable](collection []T, value T) (count int) {
|
||||
for i := range collection {
|
||||
if collection[i] == value {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// CountBy counts the number of elements in the collection for which predicate is true.
|
||||
// Play: https://go.dev/play/p/ByQbNYQQi4X
|
||||
func CountBy[T any](collection []T, predicate func(item T) bool) (count int) {
|
||||
for i := range collection {
|
||||
if predicate(collection[i]) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// CountValues counts the number of each element in the collection.
|
||||
// Play: https://go.dev/play/p/-p-PyLT4dfy
|
||||
func CountValues[T comparable](collection []T) map[T]int {
|
||||
result := make(map[T]int)
|
||||
|
||||
for i := range collection {
|
||||
result[collection[i]]++
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// CountValuesBy counts the number of each element return from mapper function.
|
||||
// Is equivalent to chaining lo.Map and lo.CountValues.
|
||||
// Play: https://go.dev/play/p/2U0dG1SnOmS
|
||||
func CountValuesBy[T any, U comparable](collection []T, mapper func(item T) U) map[U]int {
|
||||
result := make(map[U]int)
|
||||
|
||||
for i := range collection {
|
||||
result[mapper(collection[i])]++
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Subset returns a copy of a slice from `offset` up to `length` elements. Like `slice[start:start+length]`, but does not panic on overflow.
|
||||
// Play: https://go.dev/play/p/tOQu1GhFcog
|
||||
func Subset[T any, Slice ~[]T](collection Slice, offset int, length uint) Slice {
|
||||
size := len(collection)
|
||||
|
||||
if offset < 0 {
|
||||
offset = size + offset
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
}
|
||||
|
||||
if offset > size {
|
||||
return Slice{}
|
||||
}
|
||||
|
||||
if length > uint(size)-uint(offset) {
|
||||
length = uint(size - offset)
|
||||
}
|
||||
|
||||
return collection[offset : offset+int(length)]
|
||||
}
|
||||
|
||||
// Slice returns a copy of a slice from `start` up to, but not including `end`. Like `slice[start:end]`, but does not panic on overflow.
|
||||
// Play: https://go.dev/play/p/8XWYhfMMA1h
|
||||
func Slice[T any, Slice ~[]T](collection Slice, start int, end int) Slice {
|
||||
size := len(collection)
|
||||
|
||||
if start >= end {
|
||||
return Slice{}
|
||||
}
|
||||
|
||||
if start > size {
|
||||
start = size
|
||||
}
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
if end > size {
|
||||
end = size
|
||||
}
|
||||
if end < 0 {
|
||||
end = 0
|
||||
}
|
||||
|
||||
return collection[start:end]
|
||||
}
|
||||
|
||||
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/XfPzmf9gql6
|
||||
func Replace[T comparable, Slice ~[]T](collection Slice, old T, new T, n int) Slice {
|
||||
result := make(Slice, len(collection))
|
||||
copy(result, collection)
|
||||
|
||||
for i := range result {
|
||||
if result[i] == old && n != 0 {
|
||||
result[i] = new
|
||||
n--
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ReplaceAll returns a copy of the slice with all non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/a9xZFUHfYcV
|
||||
func ReplaceAll[T comparable, Slice ~[]T](collection Slice, old T, new T) Slice {
|
||||
return Replace(collection, old, new, -1)
|
||||
}
|
||||
|
||||
// Compact returns a slice of all non-zero elements.
|
||||
// Play: https://go.dev/play/p/tXiy-iK6PAc
|
||||
func Compact[T comparable, Slice ~[]T](collection Slice) Slice {
|
||||
var zero T
|
||||
|
||||
result := make(Slice, 0, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
if collection[i] != zero {
|
||||
result = append(result, collection[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSorted checks if a slice is sorted.
|
||||
// Play: https://go.dev/play/p/mc3qR-t4mcx
|
||||
func IsSorted[T constraints.Ordered](collection []T) bool {
|
||||
for i := 1; i < len(collection); i++ {
|
||||
if collection[i-1] > collection[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsSortedByKey checks if a slice is sorted by iteratee.
|
||||
// Play: https://go.dev/play/p/wiG6XyBBu49
|
||||
func IsSortedByKey[T any, K constraints.Ordered](collection []T, iteratee func(item T) K) bool {
|
||||
size := len(collection)
|
||||
|
||||
for i := 0; i < size-1; i++ {
|
||||
if iteratee(collection[i]) > iteratee(collection[i+1]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Splice inserts multiple elements at index i. A negative index counts back
|
||||
// from the end of the slice. The helper is protected against overflow errors.
|
||||
// Play: https://go.dev/play/p/G5_GhkeSUBA
|
||||
func Splice[T any, Slice ~[]T](collection Slice, i int, elements ...T) Slice {
|
||||
sizeCollection := len(collection)
|
||||
sizeElements := len(elements)
|
||||
output := make(Slice, 0, sizeCollection+sizeElements) // preallocate memory for the output slice
|
||||
|
||||
if sizeElements == 0 {
|
||||
return append(output, collection...) // simple copy
|
||||
} else if i > sizeCollection {
|
||||
// positive overflow
|
||||
return append(append(output, collection...), elements...)
|
||||
} else if i < -sizeCollection {
|
||||
// negative overflow
|
||||
return append(append(output, elements...), collection...)
|
||||
} else if i < 0 {
|
||||
// backward
|
||||
i = sizeCollection + i
|
||||
}
|
||||
|
||||
return append(append(append(output, collection[:i]...), elements...), collection[i:]...)
|
||||
}
|
||||
234
vendor/github.com/samber/lo/string.go
generated
vendored
Normal file
234
vendor/github.com/samber/lo/string.go
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
package lo
|
||||
|
||||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/samber/lo/internal/rand"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
var (
|
||||
LowerCaseLettersCharset = []rune("abcdefghijklmnopqrstuvwxyz")
|
||||
UpperCaseLettersCharset = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
LettersCharset = append(LowerCaseLettersCharset, UpperCaseLettersCharset...)
|
||||
NumbersCharset = []rune("0123456789")
|
||||
AlphanumericCharset = append(LettersCharset, NumbersCharset...)
|
||||
SpecialCharset = []rune("!@#$%^&*()_+-=[]{}|;':\",./<>?")
|
||||
AllCharset = append(AlphanumericCharset, SpecialCharset...)
|
||||
|
||||
// bearer:disable go_lang_permissive_regex_validation
|
||||
splitWordReg = regexp.MustCompile(`([a-z])([A-Z0-9])|([a-zA-Z])([0-9])|([0-9])([a-zA-Z])|([A-Z])([A-Z])([a-z])`)
|
||||
// bearer:disable go_lang_permissive_regex_validation
|
||||
splitNumberLetterReg = regexp.MustCompile(`([0-9])([a-zA-Z])`)
|
||||
maximumCapacity = math.MaxInt>>1 + 1
|
||||
)
|
||||
|
||||
// RandomString return a random string.
|
||||
// Play: https://go.dev/play/p/rRseOQVVum4
|
||||
func RandomString(size int, charset []rune) string {
|
||||
if size <= 0 {
|
||||
panic("lo.RandomString: Size parameter must be greater than 0")
|
||||
}
|
||||
if len(charset) <= 0 {
|
||||
panic("lo.RandomString: Charset parameter must not be empty")
|
||||
}
|
||||
|
||||
// see https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go
|
||||
sb := strings.Builder{}
|
||||
sb.Grow(size)
|
||||
// Calculate the number of bits required to represent the charset,
|
||||
// e.g., for 62 characters, it would need 6 bits (since 62 -> 64 = 2^6)
|
||||
letterIdBits := int(math.Log2(float64(nearestPowerOfTwo(len(charset)))))
|
||||
// Determine the corresponding bitmask,
|
||||
// e.g., for 62 characters, the bitmask would be 111111.
|
||||
var letterIdMask int64 = 1<<letterIdBits - 1
|
||||
// Available count, since rand.Int64() returns a non-negative number, the first bit is fixed, so there are 63 random bits
|
||||
// e.g., for 62 characters, this value is 10 (63 / 6).
|
||||
letterIdMax := 63 / letterIdBits
|
||||
// Generate the random string in a loop.
|
||||
for i, cache, remain := size-1, rand.Int64(), letterIdMax; i >= 0; {
|
||||
// Regenerate the random number if all available bits have been used
|
||||
if remain == 0 {
|
||||
cache, remain = rand.Int64(), letterIdMax
|
||||
}
|
||||
// Select a character from the charset
|
||||
if idx := int(cache & letterIdMask); idx < len(charset) {
|
||||
sb.WriteRune(charset[idx])
|
||||
i--
|
||||
}
|
||||
// Shift the bits to the right to prepare for the next character selection,
|
||||
// e.g., for 62 characters, shift by 6 bits.
|
||||
cache >>= letterIdBits
|
||||
// Decrease the remaining number of uses for the current random number.
|
||||
remain--
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// nearestPowerOfTwo returns the nearest power of two.
|
||||
func nearestPowerOfTwo(cap int) int {
|
||||
n := cap - 1
|
||||
n |= n >> 1
|
||||
n |= n >> 2
|
||||
n |= n >> 4
|
||||
n |= n >> 8
|
||||
n |= n >> 16
|
||||
if n < 0 {
|
||||
return 1
|
||||
}
|
||||
if n >= maximumCapacity {
|
||||
return maximumCapacity
|
||||
}
|
||||
return n + 1
|
||||
}
|
||||
|
||||
// Substring return part of a string.
|
||||
// Play: https://go.dev/play/p/TQlxQi82Lu1
|
||||
func Substring[T ~string](str T, offset int, length uint) T {
|
||||
rs := []rune(str)
|
||||
size := len(rs)
|
||||
|
||||
if offset < 0 {
|
||||
offset = size + offset
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
}
|
||||
|
||||
if offset >= size {
|
||||
return Empty[T]()
|
||||
}
|
||||
|
||||
if length > uint(size)-uint(offset) {
|
||||
length = uint(size - offset)
|
||||
}
|
||||
|
||||
return T(strings.ReplaceAll(string(rs[offset:offset+int(length)]), "\x00", ""))
|
||||
}
|
||||
|
||||
// ChunkString returns an array of strings split into groups the length of size. If array can't be split evenly,
|
||||
// the final chunk will be the remaining elements.
|
||||
// Play: https://go.dev/play/p/__FLTuJVz54
|
||||
func ChunkString[T ~string](str T, size int) []T {
|
||||
if size <= 0 {
|
||||
panic("lo.ChunkString: Size parameter must be greater than 0")
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
return []T{""}
|
||||
}
|
||||
|
||||
if size >= len(str) {
|
||||
return []T{str}
|
||||
}
|
||||
|
||||
var chunks = make([]T, 0, ((len(str)-1)/size)+1)
|
||||
currentLen := 0
|
||||
currentStart := 0
|
||||
for i := range str {
|
||||
if currentLen == size {
|
||||
chunks = append(chunks, str[currentStart:i])
|
||||
currentLen = 0
|
||||
currentStart = i
|
||||
}
|
||||
currentLen++
|
||||
}
|
||||
chunks = append(chunks, str[currentStart:])
|
||||
return chunks
|
||||
}
|
||||
|
||||
// RuneLength is an alias to utf8.RuneCountInString which returns the number of runes in string.
|
||||
// Play: https://go.dev/play/p/tuhgW_lWY8l
|
||||
func RuneLength(str string) int {
|
||||
return utf8.RuneCountInString(str)
|
||||
}
|
||||
|
||||
// PascalCase converts string to pascal case.
|
||||
func PascalCase(str string) string {
|
||||
items := Words(str)
|
||||
for i := range items {
|
||||
items[i] = Capitalize(items[i])
|
||||
}
|
||||
return strings.Join(items, "")
|
||||
}
|
||||
|
||||
// CamelCase converts string to camel case.
|
||||
func CamelCase(str string) string {
|
||||
items := Words(str)
|
||||
for i, item := range items {
|
||||
item = strings.ToLower(item)
|
||||
if i > 0 {
|
||||
item = Capitalize(item)
|
||||
}
|
||||
items[i] = item
|
||||
}
|
||||
return strings.Join(items, "")
|
||||
}
|
||||
|
||||
// KebabCase converts string to kebab case.
|
||||
func KebabCase(str string) string {
|
||||
items := Words(str)
|
||||
for i := range items {
|
||||
items[i] = strings.ToLower(items[i])
|
||||
}
|
||||
return strings.Join(items, "-")
|
||||
}
|
||||
|
||||
// SnakeCase converts string to snake case.
|
||||
func SnakeCase(str string) string {
|
||||
items := Words(str)
|
||||
for i := range items {
|
||||
items[i] = strings.ToLower(items[i])
|
||||
}
|
||||
return strings.Join(items, "_")
|
||||
}
|
||||
|
||||
// Words splits string into an array of its words.
|
||||
func Words(str string) []string {
|
||||
str = splitWordReg.ReplaceAllString(str, `$1$3$5$7 $2$4$6$8$9`)
|
||||
// example: Int8Value => Int 8Value => Int 8 Value
|
||||
str = splitNumberLetterReg.ReplaceAllString(str, "$1 $2")
|
||||
var result strings.Builder
|
||||
for _, r := range str {
|
||||
if unicode.IsLetter(r) || unicode.IsDigit(r) {
|
||||
result.WriteRune(r)
|
||||
} else {
|
||||
result.WriteRune(' ')
|
||||
}
|
||||
}
|
||||
return strings.Fields(result.String())
|
||||
}
|
||||
|
||||
// Capitalize converts the first character of string to upper case and the remaining to lower case.
|
||||
func Capitalize(str string) string {
|
||||
return cases.Title(language.English).String(str)
|
||||
}
|
||||
|
||||
// Ellipsis trims and truncates a string to a specified length **in bytes** and appends an ellipsis
|
||||
// if truncated. If the string contains non-ASCII characters (which may occupy multiple bytes in UTF-8),
|
||||
// truncating by byte length may split a character in the middle, potentially resulting in garbled output.
|
||||
func Ellipsis(str string, length int) string {
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
if len(str) > length {
|
||||
if len(str) < 3 || length < 3 {
|
||||
return "..."
|
||||
}
|
||||
return strings.TrimSpace(str[0:length-3]) + "..."
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// Elipse trims and truncates a string to a specified length and appends an ellipsis if truncated.
|
||||
//
|
||||
// Deprecated: Use Ellipsis instead.
|
||||
func Elipse(str string, length int) string {
|
||||
return Ellipsis(str, length)
|
||||
}
|
||||
85
vendor/github.com/samber/lo/time.go
generated
vendored
Normal file
85
vendor/github.com/samber/lo/time.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package lo
|
||||
|
||||
import "time"
|
||||
|
||||
// Duration returns the time taken to execute a function.
|
||||
func Duration(cb func()) time.Duration {
|
||||
return Duration0(cb)
|
||||
}
|
||||
|
||||
// Duration0 returns the time taken to execute a function.
|
||||
func Duration0(cb func()) time.Duration {
|
||||
start := time.Now()
|
||||
cb()
|
||||
return time.Since(start)
|
||||
}
|
||||
|
||||
// Duration1 returns the time taken to execute a function.
|
||||
func Duration1[A any](cb func() A) (A, time.Duration) {
|
||||
start := time.Now()
|
||||
a := cb()
|
||||
return a, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration2 returns the time taken to execute a function.
|
||||
func Duration2[A, B any](cb func() (A, B)) (A, B, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b := cb()
|
||||
return a, b, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration3 returns the time taken to execute a function.
|
||||
func Duration3[A, B, C any](cb func() (A, B, C)) (A, B, C, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c := cb()
|
||||
return a, b, c, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration4 returns the time taken to execute a function.
|
||||
func Duration4[A, B, C, D any](cb func() (A, B, C, D)) (A, B, C, D, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d := cb()
|
||||
return a, b, c, d, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration5 returns the time taken to execute a function.
|
||||
func Duration5[A, B, C, D, E any](cb func() (A, B, C, D, E)) (A, B, C, D, E, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d, e := cb()
|
||||
return a, b, c, d, e, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration6 returns the time taken to execute a function.
|
||||
func Duration6[A, B, C, D, E, F any](cb func() (A, B, C, D, E, F)) (A, B, C, D, E, F, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d, e, f := cb()
|
||||
return a, b, c, d, e, f, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration7 returns the time taken to execute a function.
|
||||
func Duration7[A, B, C, D, E, F, G any](cb func() (A, B, C, D, E, F, G)) (A, B, C, D, E, F, G, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d, e, f, g := cb()
|
||||
return a, b, c, d, e, f, g, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration8 returns the time taken to execute a function.
|
||||
func Duration8[A, B, C, D, E, F, G, H any](cb func() (A, B, C, D, E, F, G, H)) (A, B, C, D, E, F, G, H, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d, e, f, g, h := cb()
|
||||
return a, b, c, d, e, f, g, h, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration9 returns the time taken to execute a function.
|
||||
func Duration9[A, B, C, D, E, F, G, H, I any](cb func() (A, B, C, D, E, F, G, H, I)) (A, B, C, D, E, F, G, H, I, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d, e, f, g, h, i := cb()
|
||||
return a, b, c, d, e, f, g, h, i, time.Since(start)
|
||||
}
|
||||
|
||||
// Duration10 returns the time taken to execute a function.
|
||||
func Duration10[A, B, C, D, E, F, G, H, I, J any](cb func() (A, B, C, D, E, F, G, H, I, J)) (A, B, C, D, E, F, G, H, I, J, time.Duration) {
|
||||
start := time.Now()
|
||||
a, b, c, d, e, f, g, h, i, j := cb()
|
||||
return a, b, c, d, e, f, g, h, i, j, time.Since(start)
|
||||
}
|
||||
1149
vendor/github.com/samber/lo/tuples.go
generated
vendored
Normal file
1149
vendor/github.com/samber/lo/tuples.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
189
vendor/github.com/samber/lo/type_manipulation.go
generated
vendored
Normal file
189
vendor/github.com/samber/lo/type_manipulation.go
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
package lo
|
||||
|
||||
import "reflect"
|
||||
|
||||
// IsNil checks if a value is nil or if it's a reference type with a nil underlying value.
|
||||
func IsNil(x any) bool {
|
||||
defer func() { recover() }() // nolint:errcheck
|
||||
return x == nil || reflect.ValueOf(x).IsNil()
|
||||
}
|
||||
|
||||
// IsNotNil checks if a value is not nil or if it's not a reference type with a nil underlying value.
|
||||
func IsNotNil(x any) bool {
|
||||
return !IsNil(x)
|
||||
}
|
||||
|
||||
// ToPtr returns a pointer copy of value.
|
||||
func ToPtr[T any](x T) *T {
|
||||
return &x
|
||||
}
|
||||
|
||||
// Nil returns a nil pointer of type.
|
||||
func Nil[T any]() *T {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmptyableToPtr returns a pointer copy of value if it's nonzero.
|
||||
// Otherwise, returns nil pointer.
|
||||
func EmptyableToPtr[T any](x T) *T {
|
||||
// 🤮
|
||||
isZero := reflect.ValueOf(&x).Elem().IsZero()
|
||||
if isZero {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &x
|
||||
}
|
||||
|
||||
// FromPtr returns the pointer value or empty.
|
||||
func FromPtr[T any](x *T) T {
|
||||
if x == nil {
|
||||
return Empty[T]()
|
||||
}
|
||||
|
||||
return *x
|
||||
}
|
||||
|
||||
// FromPtrOr returns the pointer value or the fallback value.
|
||||
func FromPtrOr[T any](x *T, fallback T) T {
|
||||
if x == nil {
|
||||
return fallback
|
||||
}
|
||||
|
||||
return *x
|
||||
}
|
||||
|
||||
// ToSlicePtr returns a slice of pointer copy of value.
|
||||
func ToSlicePtr[T any](collection []T) []*T {
|
||||
result := make([]*T, len(collection))
|
||||
|
||||
for i := range collection {
|
||||
result[i] = &collection[i]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FromSlicePtr returns a slice with the pointer values.
|
||||
// Returns a zero value in case of a nil pointer element.
|
||||
func FromSlicePtr[T any](collection []*T) []T {
|
||||
return Map(collection, func(x *T, _ int) T {
|
||||
if x == nil {
|
||||
return Empty[T]()
|
||||
}
|
||||
return *x
|
||||
})
|
||||
}
|
||||
|
||||
// FromSlicePtrOr returns a slice with the pointer values or the fallback value.
|
||||
// Play: https://go.dev/play/p/lbunFvzlUDX
|
||||
func FromSlicePtrOr[T any](collection []*T, fallback T) []T {
|
||||
return Map(collection, func(x *T, _ int) T {
|
||||
if x == nil {
|
||||
return fallback
|
||||
}
|
||||
return *x
|
||||
})
|
||||
}
|
||||
|
||||
// ToAnySlice returns a slice with all elements mapped to `any` type
|
||||
func ToAnySlice[T any](collection []T) []any {
|
||||
result := make([]any, len(collection))
|
||||
for i := range collection {
|
||||
result[i] = collection[i]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// FromAnySlice returns an `any` slice with all elements mapped to a type.
|
||||
// Returns false in case of type conversion failure.
|
||||
func FromAnySlice[T any](in []any) (out []T, ok bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
out = []T{}
|
||||
ok = false
|
||||
}
|
||||
}()
|
||||
|
||||
result := make([]T, len(in))
|
||||
for i := range in {
|
||||
result[i] = in[i].(T)
|
||||
}
|
||||
return result, true
|
||||
}
|
||||
|
||||
// Empty returns the zero value (https://go.dev/ref/spec#The_zero_value).
|
||||
func Empty[T any]() T {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
// IsEmpty returns true if argument is a zero value.
|
||||
func IsEmpty[T comparable](v T) bool {
|
||||
var zero T
|
||||
return zero == v
|
||||
}
|
||||
|
||||
// IsNotEmpty returns true if argument is not a zero value.
|
||||
func IsNotEmpty[T comparable](v T) bool {
|
||||
var zero T
|
||||
return zero != v
|
||||
}
|
||||
|
||||
// Coalesce returns the first non-empty arguments. Arguments must be comparable.
|
||||
func Coalesce[T comparable](values ...T) (result T, ok bool) {
|
||||
for i := range values {
|
||||
if values[i] != result {
|
||||
result = values[i]
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CoalesceOrEmpty returns the first non-empty arguments. Arguments must be comparable.
|
||||
func CoalesceOrEmpty[T comparable](v ...T) T {
|
||||
result, _ := Coalesce(v...)
|
||||
return result
|
||||
}
|
||||
|
||||
// CoalesceSlice returns the first non-zero slice.
|
||||
func CoalesceSlice[T any](v ...[]T) ([]T, bool) {
|
||||
for i := range v {
|
||||
if v[i] != nil && len(v[i]) > 0 {
|
||||
return v[i], true
|
||||
}
|
||||
}
|
||||
return []T{}, false
|
||||
}
|
||||
|
||||
// CoalesceSliceOrEmpty returns the first non-zero slice.
|
||||
func CoalesceSliceOrEmpty[T any](v ...[]T) []T {
|
||||
for i := range v {
|
||||
if v[i] != nil && len(v[i]) > 0 {
|
||||
return v[i]
|
||||
}
|
||||
}
|
||||
return []T{}
|
||||
}
|
||||
|
||||
// CoalesceMap returns the first non-zero map.
|
||||
func CoalesceMap[K comparable, V any](v ...map[K]V) (map[K]V, bool) {
|
||||
for i := range v {
|
||||
if v[i] != nil && len(v[i]) > 0 {
|
||||
return v[i], true
|
||||
}
|
||||
}
|
||||
return map[K]V{}, false
|
||||
}
|
||||
|
||||
// CoalesceMapOrEmpty returns the first non-zero map.
|
||||
func CoalesceMapOrEmpty[K comparable, V any](v ...map[K]V) map[K]V {
|
||||
for i := range v {
|
||||
if v[i] != nil && len(v[i]) > 0 {
|
||||
return v[i]
|
||||
}
|
||||
}
|
||||
return map[K]V{}
|
||||
}
|
||||
123
vendor/github.com/samber/lo/types.go
generated
vendored
Normal file
123
vendor/github.com/samber/lo/types.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package lo
|
||||
|
||||
// Entry defines a key/value pairs.
|
||||
type Entry[K comparable, V any] struct {
|
||||
Key K
|
||||
Value V
|
||||
}
|
||||
|
||||
// Tuple2 is a group of 2 elements (pair).
|
||||
type Tuple2[A, B any] struct {
|
||||
A A
|
||||
B B
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple2[A, B]) Unpack() (A, B) {
|
||||
return t.A, t.B
|
||||
}
|
||||
|
||||
// Tuple3 is a group of 3 elements.
|
||||
type Tuple3[A, B, C any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple3[A, B, C]) Unpack() (A, B, C) {
|
||||
return t.A, t.B, t.C
|
||||
}
|
||||
|
||||
// Tuple4 is a group of 4 elements.
|
||||
type Tuple4[A, B, C, D any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple4[A, B, C, D]) Unpack() (A, B, C, D) {
|
||||
return t.A, t.B, t.C, t.D
|
||||
}
|
||||
|
||||
// Tuple5 is a group of 5 elements.
|
||||
type Tuple5[A, B, C, D, E any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
E E
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple5[A, B, C, D, E]) Unpack() (A, B, C, D, E) {
|
||||
return t.A, t.B, t.C, t.D, t.E
|
||||
}
|
||||
|
||||
// Tuple6 is a group of 6 elements.
|
||||
type Tuple6[A, B, C, D, E, F any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
E E
|
||||
F F
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple6[A, B, C, D, E, F]) Unpack() (A, B, C, D, E, F) {
|
||||
return t.A, t.B, t.C, t.D, t.E, t.F
|
||||
}
|
||||
|
||||
// Tuple7 is a group of 7 elements.
|
||||
type Tuple7[A, B, C, D, E, F, G any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
E E
|
||||
F F
|
||||
G G
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple7[A, B, C, D, E, F, G]) Unpack() (A, B, C, D, E, F, G) {
|
||||
return t.A, t.B, t.C, t.D, t.E, t.F, t.G
|
||||
}
|
||||
|
||||
// Tuple8 is a group of 8 elements.
|
||||
type Tuple8[A, B, C, D, E, F, G, H any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
E E
|
||||
F F
|
||||
G G
|
||||
H H
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple8[A, B, C, D, E, F, G, H]) Unpack() (A, B, C, D, E, F, G, H) {
|
||||
return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H
|
||||
}
|
||||
|
||||
// Tuple9 is a group of 9 elements.
|
||||
type Tuple9[A, B, C, D, E, F, G, H, I any] struct {
|
||||
A A
|
||||
B B
|
||||
C C
|
||||
D D
|
||||
E E
|
||||
F F
|
||||
G G
|
||||
H H
|
||||
I I
|
||||
}
|
||||
|
||||
// Unpack returns values contained in tuple.
|
||||
func (t Tuple9[A, B, C, D, E, F, G, H, I]) Unpack() (A, B, C, D, E, F, G, H, I) {
|
||||
return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H, t.I
|
||||
}
|
||||
38
vendor/github.com/samber/slog-common/.gitignore
generated
vendored
Normal file
38
vendor/github.com/samber/slog-common/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/go
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=go
|
||||
|
||||
### Go ###
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
### Go Patch ###
|
||||
/vendor/
|
||||
/Godeps/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/go
|
||||
|
||||
cover.out
|
||||
cover.html
|
||||
.vscode
|
||||
|
||||
.idea/
|
||||
21
vendor/github.com/samber/slog-common/LICENSE
generated
vendored
Normal file
21
vendor/github.com/samber/slog-common/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Samuel Berthe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
41
vendor/github.com/samber/slog-common/Makefile
generated
vendored
Normal file
41
vendor/github.com/samber/slog-common/Makefile
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
build:
|
||||
go build -v ./...
|
||||
|
||||
test:
|
||||
go test -race -v ./...
|
||||
watch-test:
|
||||
reflex -t 50ms -s -- sh -c 'gotest -race -v ./...'
|
||||
|
||||
bench:
|
||||
go test -benchmem -count 3 -bench ./...
|
||||
watch-bench:
|
||||
reflex -t 50ms -s -- sh -c 'go test -benchmem -count 3 -bench ./...'
|
||||
|
||||
coverage:
|
||||
go test -v -coverprofile=cover.out -covermode=atomic ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
tools:
|
||||
go install github.com/cespare/reflex@latest
|
||||
go install github.com/rakyll/gotest@latest
|
||||
go install github.com/psampaz/go-mod-outdated@latest
|
||||
go install github.com/jondot/goweight@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
go get -t -u golang.org/x/tools/cmd/cover
|
||||
go install github.com/sonatype-nexus-community/nancy@latest
|
||||
go mod tidy
|
||||
|
||||
lint:
|
||||
golangci-lint run --timeout 60s --max-same-issues 50 ./...
|
||||
lint-fix:
|
||||
golangci-lint run --timeout 60s --max-same-issues 50 --fix ./...
|
||||
|
||||
audit:
|
||||
go list -json -m all | nancy sleuth
|
||||
|
||||
outdated:
|
||||
go list -u -m -json all | go-mod-outdated -update -direct
|
||||
|
||||
weight:
|
||||
goweight
|
||||
109
vendor/github.com/samber/slog-common/README.md
generated
vendored
Normal file
109
vendor/github.com/samber/slog-common/README.md
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
# Nothing to see here (internal package)
|
||||
|
||||
[](https://github.com/samber/slog-common/releases)
|
||||

|
||||
[](https://pkg.go.dev/github.com/samber/slog-common)
|
||||

|
||||
[](https://goreportcard.com/report/github.com/samber/slog-common)
|
||||
[](https://codecov.io/gh/samber/slog-common)
|
||||
[](https://github.com/samber/slog-common/graphs/contributors)
|
||||
[](./LICENSE)
|
||||
|
||||

|
||||
|
||||
A toolchain for [slog](https://pkg.go.dev/log/slog) Go library.
|
||||
|
||||
This project gathers common functions for my [slog](https://pkg.go.dev/log/slog) Go libraries:
|
||||
|
||||
<div align="center">
|
||||
<hr>
|
||||
<sup><b>Sponsored by:</b></sup>
|
||||
<br>
|
||||
<a href="https://quickwit.io?utm_campaign=github_sponsorship&utm_medium=referral&utm_content=samber-slog-common&utm_source=github">
|
||||
<div>
|
||||
<img src="https://github.com/samber/oops/assets/2951285/49aaaa2b-b8c6-4f21-909f-c12577bb6a2e" width="240" alt="Quickwit">
|
||||
</div>
|
||||
<div>
|
||||
Cloud-native search engine for observability - An OSS alternative to Splunk, Elasticsearch, Loki, and Tempo.
|
||||
</div>
|
||||
</a>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
**See also:**
|
||||
|
||||
- [slog-multi](https://github.com/samber/slog-multi): `slog.Handler` chaining, fanout, routing, failover, load balancing...
|
||||
- [slog-formatter](https://github.com/samber/slog-formatter): `slog` attribute formatting
|
||||
- [slog-sampling](https://github.com/samber/slog-sampling): `slog` sampling policy
|
||||
- [slog-mock](https://github.com/samber/slog-mock): `slog.Handler` for test purposes
|
||||
|
||||
**HTTP middlewares:**
|
||||
|
||||
- [slog-gin](https://github.com/samber/slog-gin): Gin middleware for `slog` logger
|
||||
- [slog-echo](https://github.com/samber/slog-echo): Echo middleware for `slog` logger
|
||||
- [slog-fiber](https://github.com/samber/slog-fiber): Fiber middleware for `slog` logger
|
||||
- [slog-chi](https://github.com/samber/slog-chi): Chi middleware for `slog` logger
|
||||
- [slog-http](https://github.com/samber/slog-http): `net/http` middleware for `slog` logger
|
||||
|
||||
**Loggers:**
|
||||
|
||||
- [slog-zap](https://github.com/samber/slog-zap): A `slog` handler for `Zap`
|
||||
- [slog-zerolog](https://github.com/samber/slog-zerolog): A `slog` handler for `Zerolog`
|
||||
- [slog-logrus](https://github.com/samber/slog-logrus): A `slog` handler for `Logrus`
|
||||
|
||||
**Log sinks:**
|
||||
|
||||
- [slog-datadog](https://github.com/samber/slog-datadog): A `slog` handler for `Datadog`
|
||||
- [slog-betterstack](https://github.com/samber/slog-betterstack): A `slog` handler for `Betterstack`
|
||||
- [slog-rollbar](https://github.com/samber/slog-rollbar): A `slog` handler for `Rollbar`
|
||||
- [slog-loki](https://github.com/samber/slog-loki): A `slog` handler for `Loki`
|
||||
- [slog-sentry](https://github.com/samber/slog-sentry): A `slog` handler for `Sentry`
|
||||
- [slog-syslog](https://github.com/samber/slog-syslog): A `slog` handler for `Syslog`
|
||||
- [slog-logstash](https://github.com/samber/slog-logstash): A `slog` handler for `Logstash`
|
||||
- [slog-fluentd](https://github.com/samber/slog-fluentd): A `slog` handler for `Fluentd`
|
||||
- [slog-graylog](https://github.com/samber/slog-graylog): A `slog` handler for `Graylog`
|
||||
- [slog-quickwit](https://github.com/samber/slog-quickwit): A `slog` handler for `Quickwit`
|
||||
- [slog-slack](https://github.com/samber/slog-slack): A `slog` handler for `Slack`
|
||||
- [slog-telegram](https://github.com/samber/slog-telegram): A `slog` handler for `Telegram`
|
||||
- [slog-mattermost](https://github.com/samber/slog-mattermost): A `slog` handler for `Mattermost`
|
||||
- [slog-microsoft-teams](https://github.com/samber/slog-microsoft-teams): A `slog` handler for `Microsoft Teams`
|
||||
- [slog-webhook](https://github.com/samber/slog-webhook): A `slog` handler for `Webhook`
|
||||
- [slog-kafka](https://github.com/samber/slog-kafka): A `slog` handler for `Kafka`
|
||||
- [slog-nats](https://github.com/samber/slog-nats): A `slog` handler for `NATS`
|
||||
- [slog-parquet](https://github.com/samber/slog-parquet): A `slog` handler for `Parquet` + `Object Storage`
|
||||
- [slog-channel](https://github.com/samber/slog-channel): A `slog` handler for Go channels
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
- Ping me on twitter [@samuelberthe](https://twitter.com/samuelberthe) (DMs, mentions, whatever :))
|
||||
- Fork the [project](https://github.com/samber/slog-common)
|
||||
- Fix [open issues](https://github.com/samber/slog-common/issues) or request new features
|
||||
|
||||
Don't hesitate ;)
|
||||
|
||||
```bash
|
||||
# Install some dev dependencies
|
||||
make tools
|
||||
|
||||
# Run tests
|
||||
make test
|
||||
# or
|
||||
make watch-test
|
||||
```
|
||||
|
||||
## 👤 Contributors
|
||||
|
||||

|
||||
|
||||
## 💫 Show your support
|
||||
|
||||
Give a ⭐️ if this project helped you!
|
||||
|
||||
[](https://github.com/sponsors/samber)
|
||||
|
||||
## 📝 License
|
||||
|
||||
Copyright © 2023 [Samuel Berthe](https://github.com/samber).
|
||||
|
||||
This project is [MIT](./LICENSE) licensed.
|
||||
318
vendor/github.com/samber/slog-common/attributes.go
generated
vendored
Normal file
318
vendor/github.com/samber/slog-common/attributes.go
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
package slogcommon
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type ReplaceAttrFn = func(groups []string, a slog.Attr) slog.Attr
|
||||
|
||||
func AppendRecordAttrsToAttrs(attrs []slog.Attr, groups []string, record *slog.Record) []slog.Attr {
|
||||
output := make([]slog.Attr, 0, len(attrs)+record.NumAttrs())
|
||||
output = append(output, attrs...)
|
||||
|
||||
record.Attrs(func(attr slog.Attr) bool {
|
||||
for i := len(groups) - 1; i >= 0; i-- {
|
||||
attr = slog.Group(groups[i], attr)
|
||||
}
|
||||
output = append(output, attr)
|
||||
return true
|
||||
})
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func ReplaceAttrs(fn ReplaceAttrFn, groups []string, attrs ...slog.Attr) []slog.Attr {
|
||||
for i := range attrs {
|
||||
attr := attrs[i]
|
||||
value := attr.Value.Resolve()
|
||||
if value.Kind() == slog.KindGroup {
|
||||
attrs[i].Value = slog.GroupValue(ReplaceAttrs(fn, append(groups, attr.Key), value.Group()...)...)
|
||||
} else if fn != nil {
|
||||
attrs[i] = fn(groups, attr)
|
||||
}
|
||||
}
|
||||
|
||||
return attrs
|
||||
}
|
||||
|
||||
func AttrsToMap(attrs ...slog.Attr) map[string]any {
|
||||
output := map[string]any{}
|
||||
|
||||
attrsByKey := groupValuesByKey(attrs)
|
||||
for k, values := range attrsByKey {
|
||||
v := mergeAttrValues(values...)
|
||||
if v.Kind() == slog.KindGroup {
|
||||
output[k] = AttrsToMap(v.Group()...)
|
||||
} else {
|
||||
output[k] = v.Any()
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func RecordToAttrsMap(r slog.Record) map[string]any {
|
||||
attrs := make([]slog.Attr, r.NumAttrs())
|
||||
r.Attrs(func(attr slog.Attr) bool {
|
||||
attrs = append(attrs, attr)
|
||||
return true
|
||||
})
|
||||
|
||||
return AttrsToMap(attrs...)
|
||||
}
|
||||
|
||||
func groupValuesByKey(attrs []slog.Attr) map[string][]slog.Value {
|
||||
result := map[string][]slog.Value{}
|
||||
|
||||
for _, item := range attrs {
|
||||
key := item.Key
|
||||
result[key] = append(result[key], item.Value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeAttrValues(values ...slog.Value) slog.Value {
|
||||
v := values[0]
|
||||
|
||||
for i := 1; i < len(values); i++ {
|
||||
if v.Kind() != slog.KindGroup || values[i].Kind() != slog.KindGroup {
|
||||
v = values[i]
|
||||
continue
|
||||
}
|
||||
|
||||
v = slog.GroupValue(append(v.Group(), values[i].Group()...)...)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func AttrToValue(attr slog.Attr) (string, any) {
|
||||
k := attr.Key
|
||||
v := attr.Value
|
||||
kind := v.Kind()
|
||||
|
||||
switch kind {
|
||||
case slog.KindAny:
|
||||
return k, v.Any()
|
||||
case slog.KindLogValuer:
|
||||
return k, v.Any()
|
||||
case slog.KindGroup:
|
||||
return k, AttrsToMap(v.Group()...)
|
||||
case slog.KindInt64:
|
||||
return k, v.Int64()
|
||||
case slog.KindUint64:
|
||||
return k, v.Uint64()
|
||||
case slog.KindFloat64:
|
||||
return k, v.Float64()
|
||||
case slog.KindString:
|
||||
return k, v.String()
|
||||
case slog.KindBool:
|
||||
return k, v.Bool()
|
||||
case slog.KindDuration:
|
||||
return k, v.Duration()
|
||||
case slog.KindTime:
|
||||
return k, v.Time().UTC()
|
||||
default:
|
||||
return k, AnyValueToString(v)
|
||||
}
|
||||
}
|
||||
|
||||
func AnyValueToString(v slog.Value) string {
|
||||
if tm, ok := v.Any().(encoding.TextMarshaler); ok {
|
||||
data, err := tm.MarshalText()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(data)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%+v", v.Any())
|
||||
}
|
||||
|
||||
func AttrsToString(attrs ...slog.Attr) map[string]string {
|
||||
output := make(map[string]string, len(attrs))
|
||||
|
||||
for i := range attrs {
|
||||
attr := attrs[i]
|
||||
k, v := attr.Key, attr.Value
|
||||
output[k] = ValueToString(v)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func ValueToString(v slog.Value) string {
|
||||
switch v.Kind() {
|
||||
case slog.KindAny, slog.KindLogValuer, slog.KindGroup:
|
||||
return AnyValueToString(v)
|
||||
case slog.KindInt64, slog.KindUint64, slog.KindFloat64, slog.KindString, slog.KindBool, slog.KindDuration:
|
||||
return v.String()
|
||||
case slog.KindTime:
|
||||
return v.Time().UTC().String()
|
||||
default:
|
||||
return AnyValueToString(v)
|
||||
}
|
||||
}
|
||||
|
||||
func ReplaceError(attrs []slog.Attr, errorKeys ...string) []slog.Attr {
|
||||
replaceAttr := func(groups []string, a slog.Attr) slog.Attr {
|
||||
if len(groups) > 1 {
|
||||
return a
|
||||
}
|
||||
|
||||
for i := range errorKeys {
|
||||
if a.Key == errorKeys[i] {
|
||||
if err, ok := a.Value.Any().(error); ok {
|
||||
return slog.Any(a.Key, FormatError(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
return ReplaceAttrs(replaceAttr, []string{}, attrs...)
|
||||
}
|
||||
|
||||
func ExtractError(attrs []slog.Attr, errorKeys ...string) ([]slog.Attr, error) {
|
||||
for i := range attrs {
|
||||
attr := attrs[i]
|
||||
|
||||
if !slices.Contains(errorKeys, attr.Key) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err, ok := attr.Value.Resolve().Any().(error); ok {
|
||||
output := make([]slog.Attr, 0, len(attrs)-1)
|
||||
output = append(output, attrs[:i]...)
|
||||
output = append(output, attrs[i+1:]...)
|
||||
return output, err
|
||||
}
|
||||
}
|
||||
|
||||
return attrs, nil
|
||||
}
|
||||
|
||||
func FormatErrorKey(values map[string]any, errorKeys ...string) map[string]any {
|
||||
for _, errorKey := range errorKeys {
|
||||
if err, ok := values[errorKey]; ok {
|
||||
if e, ok := err.(error); ok {
|
||||
values[errorKey] = FormatError(e)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
func FormatError(err error) map[string]any {
|
||||
return map[string]any{
|
||||
"kind": reflect.TypeOf(err).String(),
|
||||
"error": err.Error(),
|
||||
"stack": nil, // @TODO
|
||||
}
|
||||
}
|
||||
|
||||
func FormatRequest(req *http.Request, ignoreHeaders bool) map[string]any {
|
||||
output := map[string]any{
|
||||
"host": req.Host,
|
||||
"method": req.Method,
|
||||
"url": map[string]any{
|
||||
"url": req.URL.String(),
|
||||
"scheme": req.URL.Scheme,
|
||||
"host": req.URL.Host,
|
||||
"path": req.URL.Path,
|
||||
"raw_query": req.URL.RawQuery,
|
||||
"fragment": req.URL.Fragment,
|
||||
"query": lo.MapEntries(req.URL.Query(), func(key string, values []string) (string, string) {
|
||||
return key, strings.Join(values, ",")
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
if !ignoreHeaders {
|
||||
output["headers"] = lo.MapEntries(req.Header, func(key string, values []string) (string, string) {
|
||||
return key, strings.Join(values, ",")
|
||||
})
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func Source(sourceKey string, r *slog.Record) slog.Attr {
|
||||
fs := runtime.CallersFrames([]uintptr{r.PC})
|
||||
f, _ := fs.Next()
|
||||
var args []any
|
||||
if f.Function != "" {
|
||||
args = append(args, slog.String("function", f.Function))
|
||||
}
|
||||
if f.File != "" {
|
||||
args = append(args, slog.String("file", f.File))
|
||||
}
|
||||
if f.Line != 0 {
|
||||
args = append(args, slog.Int("line", f.Line))
|
||||
}
|
||||
|
||||
return slog.Group(sourceKey, args...)
|
||||
}
|
||||
|
||||
func StringSource(sourceKey string, r *slog.Record) slog.Attr {
|
||||
fs := runtime.CallersFrames([]uintptr{r.PC})
|
||||
f, _ := fs.Next()
|
||||
return slog.String(sourceKey, fmt.Sprintf("%s:%d (%s)", f.File, f.Line, f.Function))
|
||||
}
|
||||
|
||||
func FindAttribute(attrs []slog.Attr, groups []string, key string) (slog.Attr, bool) {
|
||||
// group traversal
|
||||
if len(groups) > 0 {
|
||||
for _, attr := range attrs {
|
||||
if attr.Value.Kind() == slog.KindGroup && attr.Key == groups[0] {
|
||||
attr, found := FindAttribute(attr.Value.Group(), groups[1:], key)
|
||||
if found {
|
||||
return attr, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return slog.Attr{}, false
|
||||
}
|
||||
|
||||
// starting here, groups is empty
|
||||
for _, attr := range attrs {
|
||||
if attr.Key == key {
|
||||
return attr, true
|
||||
}
|
||||
}
|
||||
|
||||
return slog.Attr{}, false
|
||||
}
|
||||
|
||||
func RemoveEmptyAttrs(attrs []slog.Attr) []slog.Attr {
|
||||
return lo.FilterMap(attrs, func(attr slog.Attr, _ int) (slog.Attr, bool) {
|
||||
if attr.Key == "" {
|
||||
return attr, false
|
||||
}
|
||||
|
||||
if attr.Value.Kind() == slog.KindGroup {
|
||||
values := RemoveEmptyAttrs(attr.Value.Group())
|
||||
if len(values) == 0 {
|
||||
return attr, false
|
||||
}
|
||||
|
||||
attr.Value = slog.GroupValue(values...)
|
||||
return attr, true
|
||||
}
|
||||
|
||||
return attr, !attr.Value.Equal(slog.Value{})
|
||||
})
|
||||
}
|
||||
24
vendor/github.com/samber/slog-common/context.go
generated
vendored
Normal file
24
vendor/github.com/samber/slog-common/context.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package slogcommon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func ContextExtractor(ctx context.Context, fns []func(ctx context.Context) []slog.Attr) []slog.Attr {
|
||||
attrs := []slog.Attr{}
|
||||
for _, fn := range fns {
|
||||
attrs = append(attrs, fn(ctx)...)
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
func ExtractFromContext(keys ...any) func(ctx context.Context) []slog.Attr {
|
||||
return func(ctx context.Context) []slog.Attr {
|
||||
attrs := make([]slog.Attr, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
attrs = append(attrs, slog.Any(key.(string), ctx.Value(key)))
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
}
|
||||
27
vendor/github.com/samber/slog-common/finder.go
generated
vendored
Normal file
27
vendor/github.com/samber/slog-common/finder.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package slogcommon
|
||||
|
||||
import "log/slog"
|
||||
|
||||
func FindAttrByKey(attrs []slog.Attr, key string) (slog.Attr, bool) {
|
||||
for i := range attrs {
|
||||
if attrs[i].Key == key {
|
||||
return attrs[i], true
|
||||
}
|
||||
}
|
||||
|
||||
return slog.Attr{}, false
|
||||
}
|
||||
|
||||
func FindAttrByGroupAndKey(attrs []slog.Attr, groups []string, key string) (slog.Attr, bool) {
|
||||
if len(groups) == 0 {
|
||||
return FindAttrByKey(attrs, key)
|
||||
}
|
||||
|
||||
for i := range attrs {
|
||||
if attrs[i].Key == key && attrs[i].Value.Kind() == slog.KindGroup {
|
||||
return FindAttrByGroupAndKey(attrs[i].Value.Group(), groups[1:], key)
|
||||
}
|
||||
}
|
||||
|
||||
return slog.Attr{}, false
|
||||
}
|
||||
65
vendor/github.com/samber/slog-common/groups.go
generated
vendored
Normal file
65
vendor/github.com/samber/slog-common/groups.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package slogcommon
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"slices"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func AppendAttrsToGroup(groups []string, actualAttrs []slog.Attr, newAttrs ...slog.Attr) []slog.Attr {
|
||||
if len(groups) == 0 {
|
||||
actualAttrsCopy := make([]slog.Attr, 0, len(actualAttrs)+len(newAttrs))
|
||||
actualAttrsCopy = append(actualAttrsCopy, actualAttrs...)
|
||||
actualAttrsCopy = append(actualAttrsCopy, newAttrs...)
|
||||
return UniqAttrs(actualAttrsCopy)
|
||||
}
|
||||
|
||||
actualAttrs = slices.Clone(actualAttrs)
|
||||
|
||||
for i := range actualAttrs {
|
||||
attr := actualAttrs[i]
|
||||
if attr.Key == groups[0] && attr.Value.Kind() == slog.KindGroup {
|
||||
actualAttrs[i] = slog.Group(groups[0], lo.ToAnySlice(AppendAttrsToGroup(groups[1:], attr.Value.Group(), newAttrs...))...)
|
||||
return actualAttrs
|
||||
}
|
||||
}
|
||||
|
||||
return UniqAttrs(
|
||||
append(
|
||||
actualAttrs,
|
||||
slog.Group(
|
||||
groups[0],
|
||||
lo.ToAnySlice(AppendAttrsToGroup(groups[1:], []slog.Attr{}, newAttrs...))...,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// @TODO: should be recursive
|
||||
func UniqAttrs(attrs []slog.Attr) []slog.Attr {
|
||||
return uniqByLast(attrs, func(item slog.Attr) string {
|
||||
return item.Key
|
||||
})
|
||||
}
|
||||
|
||||
func uniqByLast[T any, U comparable](collection []T, iteratee func(item T) U) []T {
|
||||
result := make([]T, 0, len(collection))
|
||||
seen := make(map[U]int, len(collection))
|
||||
seenIndex := 0
|
||||
|
||||
for _, item := range collection {
|
||||
key := iteratee(item)
|
||||
|
||||
if index, ok := seen[key]; ok {
|
||||
result[index] = item
|
||||
continue
|
||||
}
|
||||
|
||||
seen[key] = seenIndex
|
||||
seenIndex++
|
||||
result = append(result, item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
38
vendor/github.com/samber/slog-zerolog/v2/.gitignore
generated
vendored
Normal file
38
vendor/github.com/samber/slog-zerolog/v2/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/go
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=go
|
||||
|
||||
### Go ###
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
### Go Patch ###
|
||||
/vendor/
|
||||
/Godeps/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/go
|
||||
|
||||
cover.out
|
||||
cover.html
|
||||
.vscode
|
||||
|
||||
.idea/
|
||||
21
vendor/github.com/samber/slog-zerolog/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/samber/slog-zerolog/v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Samuel Berthe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
41
vendor/github.com/samber/slog-zerolog/v2/Makefile
generated
vendored
Normal file
41
vendor/github.com/samber/slog-zerolog/v2/Makefile
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
build:
|
||||
go build -v ./...
|
||||
|
||||
test:
|
||||
go test -race -v ./...
|
||||
watch-test:
|
||||
reflex -t 50ms -s -- sh -c 'gotest -race -v ./...'
|
||||
|
||||
bench:
|
||||
go test -benchmem -count 3 -bench ./...
|
||||
watch-bench:
|
||||
reflex -t 50ms -s -- sh -c 'go test -benchmem -count 3 -bench ./...'
|
||||
|
||||
coverage:
|
||||
go test -v -coverprofile=cover.out -covermode=atomic ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
tools:
|
||||
go install github.com/cespare/reflex@latest
|
||||
go install github.com/rakyll/gotest@latest
|
||||
go install github.com/psampaz/go-mod-outdated@latest
|
||||
go install github.com/jondot/goweight@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
go get -t -u golang.org/x/tools/cmd/cover
|
||||
go install github.com/sonatype-nexus-community/nancy@latest
|
||||
go mod tidy
|
||||
|
||||
lint:
|
||||
golangci-lint run --timeout 60s --max-same-issues 50 ./...
|
||||
lint-fix:
|
||||
golangci-lint run --timeout 60s --max-same-issues 50 --fix ./...
|
||||
|
||||
audit:
|
||||
go list -json -m all | nancy sleuth
|
||||
|
||||
outdated:
|
||||
go list -u -m -json all | go-mod-outdated -update -direct
|
||||
|
||||
weight:
|
||||
goweight
|
||||
262
vendor/github.com/samber/slog-zerolog/v2/README.md
generated
vendored
Normal file
262
vendor/github.com/samber/slog-zerolog/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
|
||||
# slog: Zerolog handler
|
||||
|
||||
[](https://github.com/samber/slog-zerolog/releases)
|
||||

|
||||
[](https://pkg.go.dev/github.com/samber/slog-zerolog)
|
||||

|
||||
[](https://goreportcard.com/report/github.com/samber/slog-zerolog)
|
||||
[](https://codecov.io/gh/samber/slog-zerolog)
|
||||
[](https://github.com/samber/slog-zerolog/graphs/contributors)
|
||||
[](./LICENSE)
|
||||
|
||||
A [Zerolog](https://github.com/rs/zerolog) Handler for [slog](https://pkg.go.dev/log/slog) Go library.
|
||||
|
||||
<div align="center">
|
||||
<hr>
|
||||
<sup><b>Sponsored by:</b></sup>
|
||||
<br>
|
||||
<a href="https://www.dash0.com?utm_campaign=148395251-samber%20github%20sponsorship&utm_source=github&utm_medium=sponsorship&utm_content=samber">
|
||||
<div>
|
||||
<img src="https://github.com/user-attachments/assets/b1f2e876-0954-4dc3-824d-935d29ba8f3f" width="200" alt="Dash0">
|
||||
</div>
|
||||
<div>
|
||||
100% OpenTelemetry-native observability platform<br>Simple to use, built on open standards, and designed for full cost control
|
||||
</div>
|
||||
</a>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
**See also:**
|
||||
|
||||
- [slog-multi](https://github.com/samber/slog-multi): `slog.Handler` chaining, fanout, routing, failover, load balancing...
|
||||
- [slog-formatter](https://github.com/samber/slog-formatter): `slog` attribute formatting
|
||||
- [slog-sampling](https://github.com/samber/slog-sampling): `slog` sampling policy
|
||||
- [slog-mock](https://github.com/samber/slog-mock): `slog.Handler` for test purposes
|
||||
|
||||
**HTTP middlewares:**
|
||||
|
||||
- [slog-gin](https://github.com/samber/slog-gin): Gin middleware for `slog` logger
|
||||
- [slog-echo](https://github.com/samber/slog-echo): Echo middleware for `slog` logger
|
||||
- [slog-fiber](https://github.com/samber/slog-fiber): Fiber middleware for `slog` logger
|
||||
- [slog-chi](https://github.com/samber/slog-chi): Chi middleware for `slog` logger
|
||||
- [slog-http](https://github.com/samber/slog-http): `net/http` middleware for `slog` logger
|
||||
|
||||
**Loggers:**
|
||||
|
||||
- [slog-zap](https://github.com/samber/slog-zap): A `slog` handler for `Zap`
|
||||
- [slog-zerolog](https://github.com/samber/slog-zerolog): A `slog` handler for `Zerolog`
|
||||
- [slog-logrus](https://github.com/samber/slog-logrus): A `slog` handler for `Logrus`
|
||||
|
||||
**Log sinks:**
|
||||
|
||||
- [slog-datadog](https://github.com/samber/slog-datadog): A `slog` handler for `Datadog`
|
||||
- [slog-betterstack](https://github.com/samber/slog-betterstack): A `slog` handler for `Betterstack`
|
||||
- [slog-rollbar](https://github.com/samber/slog-rollbar): A `slog` handler for `Rollbar`
|
||||
- [slog-loki](https://github.com/samber/slog-loki): A `slog` handler for `Loki`
|
||||
- [slog-sentry](https://github.com/samber/slog-sentry): A `slog` handler for `Sentry`
|
||||
- [slog-syslog](https://github.com/samber/slog-syslog): A `slog` handler for `Syslog`
|
||||
- [slog-logstash](https://github.com/samber/slog-logstash): A `slog` handler for `Logstash`
|
||||
- [slog-fluentd](https://github.com/samber/slog-fluentd): A `slog` handler for `Fluentd`
|
||||
- [slog-graylog](https://github.com/samber/slog-graylog): A `slog` handler for `Graylog`
|
||||
- [slog-quickwit](https://github.com/samber/slog-quickwit): A `slog` handler for `Quickwit`
|
||||
- [slog-slack](https://github.com/samber/slog-slack): A `slog` handler for `Slack`
|
||||
- [slog-telegram](https://github.com/samber/slog-telegram): A `slog` handler for `Telegram`
|
||||
- [slog-mattermost](https://github.com/samber/slog-mattermost): A `slog` handler for `Mattermost`
|
||||
- [slog-microsoft-teams](https://github.com/samber/slog-microsoft-teams): A `slog` handler for `Microsoft Teams`
|
||||
- [slog-webhook](https://github.com/samber/slog-webhook): A `slog` handler for `Webhook`
|
||||
- [slog-kafka](https://github.com/samber/slog-kafka): A `slog` handler for `Kafka`
|
||||
- [slog-nats](https://github.com/samber/slog-nats): A `slog` handler for `NATS`
|
||||
- [slog-parquet](https://github.com/samber/slog-parquet): A `slog` handler for `Parquet` + `Object Storage`
|
||||
- [slog-channel](https://github.com/samber/slog-channel): A `slog` handler for Go channels
|
||||
|
||||
## 🚀 Install
|
||||
|
||||
```sh
|
||||
go get github.com/samber/slog-zerolog/v2
|
||||
```
|
||||
|
||||
**Compatibility**: go >= 1.21
|
||||
|
||||
No breaking changes will be made to exported APIs before v3.0.0.
|
||||
|
||||
## 💡 Usage
|
||||
|
||||
GoDoc: [https://pkg.go.dev/github.com/samber/slog-zerolog/v2](https://pkg.go.dev/github.com/samber/slog-zerolog/v2)
|
||||
|
||||
### Handler options
|
||||
|
||||
```go
|
||||
type Option struct {
|
||||
// log level (default: debug)
|
||||
// you can use ZeroLogLeveler to retrieve the level from the global zerolog instance or a custom one
|
||||
Level slog.Leveler
|
||||
|
||||
// optional: zerolog logger (default: zerolog.Logger)
|
||||
Logger *zerolog.Logger
|
||||
// optional: don't add timestamp to record
|
||||
NoTimestamp bool
|
||||
|
||||
// optional: customize json payload builder
|
||||
Converter Converter
|
||||
// optional: fetch attributes from context
|
||||
AttrFromContext []func(ctx context.Context) []slog.Attr
|
||||
|
||||
// optional: see slog.HandlerOptions
|
||||
AddSource bool
|
||||
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
|
||||
}
|
||||
```
|
||||
|
||||
Other global parameters:
|
||||
|
||||
```go
|
||||
slogzerolog.SourceKey = "source"
|
||||
slogzerolog.ErrorKeys = []string{"error", "err"}
|
||||
slogzerolog.LogLevels = map[slog.Level]zerolog.Level{...}
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
slogzerolog "github.com/samber/slog-zerolog/v2"
|
||||
"os"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
zerologLogger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
logger := slog.New(slogzerolog.Option{Level: slog.LevelDebug, Logger: &zerologLogger}.NewZerologHandler())
|
||||
logger = logger.
|
||||
With("environment", "dev").
|
||||
With("release", "v1.0.0")
|
||||
|
||||
// log error
|
||||
logger.
|
||||
With("category", "sql").
|
||||
With("query.statement", "SELECT COUNT(*) FROM users;").
|
||||
With("query.duration", 1*time.Second).
|
||||
With("error", fmt.Errorf("could not count users")).
|
||||
Error("caramba!")
|
||||
|
||||
// log user signup
|
||||
logger.
|
||||
With(
|
||||
slog.Group("user",
|
||||
slog.String("id", "user-123"),
|
||||
slog.Time("created_at", time.Now()),
|
||||
),
|
||||
).
|
||||
Info("user registration")
|
||||
}
|
||||
```
|
||||
|
||||
### Tracing
|
||||
|
||||
Import the samber/slog-otel library.
|
||||
|
||||
```go
|
||||
import (
|
||||
slogzerolog "github.com/samber/slog-zerolog"
|
||||
slogotel "github.com/samber/slog-otel"
|
||||
"go.opentelemetry.io/otel/sdk/trace"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tp := trace.NewTracerProvider(
|
||||
trace.WithSampler(trace.AlwaysSample()),
|
||||
)
|
||||
tracer := tp.Tracer("hello/world")
|
||||
|
||||
ctx, span := tracer.Start(context.Background(), "foo")
|
||||
defer span.End()
|
||||
|
||||
span.AddEvent("bar")
|
||||
|
||||
logger := slog.New(
|
||||
slogzerolog.Option{
|
||||
// ...
|
||||
AttrFromContext: []func(ctx context.Context) []slog.Attr{
|
||||
slogotel.ExtractOtelAttrFromContext([]string{"tracing"}, "trace_id", "span_id"),
|
||||
},
|
||||
}.NewZerologHandler(),
|
||||
)
|
||||
|
||||
logger.ErrorContext(ctx, "a message")
|
||||
}
|
||||
```
|
||||
|
||||
### Zerolog level mapping
|
||||
|
||||
Use the `slogzerolog.ZeroLogLeveler` as `slogzerolog.Option.Level` (`slog.Leveler`) to set the `slog.Level` from
|
||||
`zerolog.Level`.
|
||||
|
||||
Currently following levels are mapped:
|
||||
|
||||
| zerolog | slog |
|
||||
|----------|-----------|
|
||||
| Trace-N | Debug-1-N |
|
||||
| Trace | Debug-1 |
|
||||
| Debug | Debug |
|
||||
| Info | Info |
|
||||
| Warn | Warn |
|
||||
| Error | Error |
|
||||
| Panic | Error |
|
||||
| Fatal | Error |
|
||||
| NoLevel | Info |
|
||||
| Disabled | Debug-1 |
|
||||
| * | Info |
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
slogzerolog "github.com/samber/slog-zerolog/v2"
|
||||
"os"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
zerologLogger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
logger := slog.New(slogzerolog.Option{Level: ZeroLogLeveler{&zerologLogger}, Logger: &zerologLogger}.NewZerologHandler())
|
||||
|
||||
logger.Trace("caramba!")
|
||||
}
|
||||
```
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
- Ping me on twitter [@samuelberthe](https://twitter.com/samuelberthe) (DMs, mentions, whatever :))
|
||||
- Fork the [project](https://github.com/samber/slog-zerolog)
|
||||
- Fix [open issues](https://github.com/samber/slog-zerolog/issues) or request new features
|
||||
|
||||
Don't hesitate ;)
|
||||
|
||||
```bash
|
||||
# Install some dev dependencies
|
||||
make tools
|
||||
|
||||
# Run tests
|
||||
make test
|
||||
# or
|
||||
make watch-test
|
||||
```
|
||||
|
||||
## 👤 Contributors
|
||||
|
||||

|
||||
|
||||
## 💫 Show your support
|
||||
|
||||
Give a ⭐️ if this project helped you!
|
||||
|
||||
[](https://github.com/sponsors/samber)
|
||||
|
||||
## 📝 License
|
||||
|
||||
Copyright © 2023 [Samuel Berthe](https://github.com/samber).
|
||||
|
||||
This project is [MIT](./LICENSE) licensed.
|
||||
30
vendor/github.com/samber/slog-zerolog/v2/converter.go
generated
vendored
Normal file
30
vendor/github.com/samber/slog-zerolog/v2/converter.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package slogzerolog
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
slogcommon "github.com/samber/slog-common"
|
||||
)
|
||||
|
||||
var SourceKey = "source"
|
||||
var ErrorKeys = []string{"error", "err"}
|
||||
|
||||
type Converter func(addSource bool, replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) map[string]any
|
||||
|
||||
func DefaultConverter(addSource bool, replaceAttr func(groups []string, a slog.Attr) slog.Attr, loggerAttr []slog.Attr, groups []string, record *slog.Record) map[string]any {
|
||||
// aggregate all attributes
|
||||
attrs := slogcommon.AppendRecordAttrsToAttrs(loggerAttr, groups, record)
|
||||
|
||||
// developer formatters
|
||||
attrs = slogcommon.ReplaceError(attrs, ErrorKeys...)
|
||||
if addSource {
|
||||
attrs = append(attrs, slogcommon.Source(SourceKey, record))
|
||||
}
|
||||
attrs = slogcommon.ReplaceAttrs(replaceAttr, []string{}, attrs...)
|
||||
attrs = slogcommon.RemoveEmptyAttrs(attrs)
|
||||
|
||||
// handler formatter
|
||||
output := slogcommon.AttrsToMap(attrs...)
|
||||
|
||||
return output
|
||||
}
|
||||
109
vendor/github.com/samber/slog-zerolog/v2/handler.go
generated
vendored
Normal file
109
vendor/github.com/samber/slog-zerolog/v2/handler.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package slogzerolog
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
slogcommon "github.com/samber/slog-common"
|
||||
)
|
||||
|
||||
type Option struct {
|
||||
// log level (default: debug)
|
||||
// you can use ZeroLogLeveler to retrieve the level from the global zerolog instance or a custom one
|
||||
Level slog.Leveler
|
||||
|
||||
// optional: zerolog logger (default: zerolog.Logger)
|
||||
Logger *zerolog.Logger
|
||||
// optional: don't add timestamp to record
|
||||
NoTimestamp bool
|
||||
|
||||
// optional: customize json payload builder
|
||||
Converter Converter
|
||||
// optional: fetch attributes from context
|
||||
AttrFromContext []func(ctx context.Context) []slog.Attr
|
||||
|
||||
// optional: see slog.HandlerOptions
|
||||
AddSource bool
|
||||
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
|
||||
}
|
||||
|
||||
func (o Option) NewZerologHandler() slog.Handler {
|
||||
if o.Level == nil {
|
||||
o.Level = slog.LevelDebug
|
||||
}
|
||||
|
||||
if o.Logger == nil {
|
||||
// should be selected lazily ?
|
||||
o.Logger = &log.Logger
|
||||
}
|
||||
|
||||
if o.AttrFromContext == nil {
|
||||
o.AttrFromContext = []func(ctx context.Context) []slog.Attr{}
|
||||
}
|
||||
|
||||
return &ZerologHandler{
|
||||
option: o,
|
||||
attrs: []slog.Attr{},
|
||||
groups: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
var _ slog.Handler = (*ZerologHandler)(nil)
|
||||
|
||||
type ZerologHandler struct {
|
||||
option Option
|
||||
attrs []slog.Attr
|
||||
groups []string
|
||||
}
|
||||
|
||||
func (h *ZerologHandler) Enabled(_ context.Context, level slog.Level) bool {
|
||||
return level >= h.option.Level.Level()
|
||||
}
|
||||
|
||||
func (h *ZerologHandler) Handle(ctx context.Context, record slog.Record) error {
|
||||
converter := DefaultConverter
|
||||
if h.option.Converter != nil {
|
||||
converter = h.option.Converter
|
||||
}
|
||||
|
||||
level := LogLevels[record.Level]
|
||||
fromContext := slogcommon.ContextExtractor(ctx, h.option.AttrFromContext)
|
||||
args := converter(h.option.AddSource, h.option.ReplaceAttr, append(h.attrs, fromContext...), h.groups, &record)
|
||||
|
||||
event := h.option.Logger.
|
||||
WithLevel(level).
|
||||
Ctx(ctx).
|
||||
CallerSkipFrame(3)
|
||||
|
||||
if !h.option.NoTimestamp {
|
||||
event.Time(zerolog.TimestampFieldName, record.Time)
|
||||
}
|
||||
|
||||
event.Fields(args).Msg(record.Message)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ZerologHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
return &ZerologHandler{
|
||||
option: h.option,
|
||||
attrs: slogcommon.AppendAttrsToGroup(h.groups, h.attrs, attrs...),
|
||||
groups: h.groups,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ZerologHandler) WithGroup(name string) slog.Handler {
|
||||
// https://cs.opensource.google/go/x/exp/+/46b07846:slog/handler.go;l=247
|
||||
if name == "" {
|
||||
return h
|
||||
}
|
||||
|
||||
return &ZerologHandler{
|
||||
option: h.option,
|
||||
attrs: h.attrs,
|
||||
groups: append(h.groups, name),
|
||||
}
|
||||
}
|
||||
58
vendor/github.com/samber/slog-zerolog/v2/zerolog.go
generated
vendored
Normal file
58
vendor/github.com/samber/slog-zerolog/v2/zerolog.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package slogzerolog
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var LogLevels = map[slog.Level]zerolog.Level{
|
||||
slog.LevelDebug: zerolog.DebugLevel,
|
||||
slog.LevelInfo: zerolog.InfoLevel,
|
||||
slog.LevelWarn: zerolog.WarnLevel,
|
||||
slog.LevelError: zerolog.ErrorLevel,
|
||||
}
|
||||
|
||||
var reverseLogLevels map[zerolog.Level]slog.Level
|
||||
|
||||
func init() {
|
||||
reverseLogLevels = map[zerolog.Level]slog.Level{}
|
||||
for level, z := range LogLevels {
|
||||
reverseLogLevels[z] = level
|
||||
}
|
||||
}
|
||||
|
||||
// ZeroLogLeveler can be used for Option.Level (implements slog.Leveler).
|
||||
// If no Logger is provided, the global zerolog.Logger is used.
|
||||
type ZeroLogLeveler struct {
|
||||
// optional: zerolog logger (default: log.Logger)
|
||||
Logger *zerolog.Logger
|
||||
}
|
||||
|
||||
var _ slog.Leveler = ZeroLogLeveler{}
|
||||
|
||||
func (z ZeroLogLeveler) Level() slog.Level {
|
||||
var logger = log.Logger
|
||||
if z.Logger != nil {
|
||||
logger = *z.Logger
|
||||
}
|
||||
zeroLogLevel := logger.GetLevel()
|
||||
level, ok := reverseLogLevels[zeroLogLevel]
|
||||
if !ok {
|
||||
switch zeroLogLevel {
|
||||
case zerolog.PanicLevel, zerolog.FatalLevel:
|
||||
return slog.LevelError
|
||||
case zerolog.NoLevel:
|
||||
return slog.LevelInfo
|
||||
case zerolog.Disabled:
|
||||
return slog.LevelDebug - 1
|
||||
default:
|
||||
if zeroLogLevel < zerolog.DebugLevel {
|
||||
return slog.Level(int(slog.LevelDebug) + int(zeroLogLevel))
|
||||
}
|
||||
return slog.LevelInfo
|
||||
}
|
||||
}
|
||||
return level
|
||||
}
|
||||
3
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/README.md
generated
vendored
3
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/README.md
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Semconv v1.10.0
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.10.0)
|
||||
9
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/doc.go
generated
vendored
9
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/doc.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package semconv implements OpenTelemetry semantic conventions.
|
||||
//
|
||||
// OpenTelemetry semantic conventions are agreed standardized naming
|
||||
// patterns for OpenTelemetry things. This package represents the conventions
|
||||
// as of the v1.10.0 version of the OpenTelemetry specification.
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
9
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/exception.go
generated
vendored
9
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/exception.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
|
||||
const (
|
||||
// ExceptionEventName is the name of the Span event representing an exception.
|
||||
ExceptionEventName = "exception"
|
||||
)
|
||||
103
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/http.go
generated
vendored
103
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/http.go
generated
vendored
@@ -1,103 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/semconv/internal"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// HTTP scheme attributes.
|
||||
var (
|
||||
HTTPSchemeHTTP = HTTPSchemeKey.String("http")
|
||||
HTTPSchemeHTTPS = HTTPSchemeKey.String("https")
|
||||
)
|
||||
|
||||
var sc = &internal.SemanticConventions{
|
||||
EnduserIDKey: EnduserIDKey,
|
||||
HTTPClientIPKey: HTTPClientIPKey,
|
||||
HTTPFlavorKey: HTTPFlavorKey,
|
||||
HTTPHostKey: HTTPHostKey,
|
||||
HTTPMethodKey: HTTPMethodKey,
|
||||
HTTPRequestContentLengthKey: HTTPRequestContentLengthKey,
|
||||
HTTPRouteKey: HTTPRouteKey,
|
||||
HTTPSchemeHTTP: HTTPSchemeHTTP,
|
||||
HTTPSchemeHTTPS: HTTPSchemeHTTPS,
|
||||
HTTPServerNameKey: HTTPServerNameKey,
|
||||
HTTPStatusCodeKey: HTTPStatusCodeKey,
|
||||
HTTPTargetKey: HTTPTargetKey,
|
||||
HTTPURLKey: HTTPURLKey,
|
||||
HTTPUserAgentKey: HTTPUserAgentKey,
|
||||
NetHostIPKey: NetHostIPKey,
|
||||
NetHostNameKey: NetHostNameKey,
|
||||
NetHostPortKey: NetHostPortKey,
|
||||
NetPeerIPKey: NetPeerIPKey,
|
||||
NetPeerNameKey: NetPeerNameKey,
|
||||
NetPeerPortKey: NetPeerPortKey,
|
||||
NetTransportIP: NetTransportIP,
|
||||
NetTransportOther: NetTransportOther,
|
||||
NetTransportTCP: NetTransportTCP,
|
||||
NetTransportUDP: NetTransportUDP,
|
||||
NetTransportUnix: NetTransportUnix,
|
||||
}
|
||||
|
||||
// NetAttributesFromHTTPRequest generates attributes of the net
|
||||
// namespace as specified by the OpenTelemetry specification for a
|
||||
// span. The network parameter is a string that net.Dial function
|
||||
// from standard library can understand.
|
||||
func NetAttributesFromHTTPRequest(network string, request *http.Request) []attribute.KeyValue {
|
||||
return sc.NetAttributesFromHTTPRequest(network, request)
|
||||
}
|
||||
|
||||
// EndUserAttributesFromHTTPRequest generates attributes of the
|
||||
// enduser namespace as specified by the OpenTelemetry specification
|
||||
// for a span.
|
||||
func EndUserAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
|
||||
return sc.EndUserAttributesFromHTTPRequest(request)
|
||||
}
|
||||
|
||||
// HTTPClientAttributesFromHTTPRequest generates attributes of the
|
||||
// http namespace as specified by the OpenTelemetry specification for
|
||||
// a span on the client side.
|
||||
func HTTPClientAttributesFromHTTPRequest(request *http.Request) []attribute.KeyValue {
|
||||
return sc.HTTPClientAttributesFromHTTPRequest(request)
|
||||
}
|
||||
|
||||
// HTTPServerMetricAttributesFromHTTPRequest generates low-cardinality attributes
|
||||
// to be used with server-side HTTP metrics.
|
||||
func HTTPServerMetricAttributesFromHTTPRequest(serverName string, request *http.Request) []attribute.KeyValue {
|
||||
return sc.HTTPServerMetricAttributesFromHTTPRequest(serverName, request)
|
||||
}
|
||||
|
||||
// HTTPServerAttributesFromHTTPRequest generates attributes of the
|
||||
// http namespace as specified by the OpenTelemetry specification for
|
||||
// a span on the server side. Currently, only basic authentication is
|
||||
// supported.
|
||||
func HTTPServerAttributesFromHTTPRequest(serverName, route string, request *http.Request) []attribute.KeyValue {
|
||||
return sc.HTTPServerAttributesFromHTTPRequest(serverName, route, request)
|
||||
}
|
||||
|
||||
// HTTPAttributesFromHTTPStatusCode generates attributes of the http
|
||||
// namespace as specified by the OpenTelemetry specification for a
|
||||
// span.
|
||||
func HTTPAttributesFromHTTPStatusCode(code int) []attribute.KeyValue {
|
||||
return sc.HTTPAttributesFromHTTPStatusCode(code)
|
||||
}
|
||||
|
||||
// SpanStatusFromHTTPStatusCode generates a status code and a message
|
||||
// as specified by the OpenTelemetry specification for a span.
|
||||
func SpanStatusFromHTTPStatusCode(code int) (codes.Code, string) {
|
||||
return internal.SpanStatusFromHTTPStatusCode(code)
|
||||
}
|
||||
|
||||
// SpanStatusFromHTTPStatusCodeAndSpanKind generates a status code and a message
|
||||
// as specified by the OpenTelemetry specification for a span.
|
||||
// Exclude 4xx for SERVER to set the appropriate status.
|
||||
func SpanStatusFromHTTPStatusCodeAndSpanKind(code int, spanKind trace.SpanKind) (codes.Code, string) {
|
||||
return internal.SpanStatusFromHTTPStatusCodeAndSpanKind(code, spanKind)
|
||||
}
|
||||
970
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/resource.go
generated
vendored
970
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/resource.go
generated
vendored
@@ -1,970 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated from semantic convention specification. DO NOT EDIT.
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
|
||||
import "go.opentelemetry.io/otel/attribute"
|
||||
|
||||
// A cloud environment (e.g. GCP, Azure, AWS)
|
||||
const (
|
||||
// Name of the cloud provider.
|
||||
//
|
||||
// Type: Enum
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
CloudProviderKey = attribute.Key("cloud.provider")
|
||||
// The cloud account ID the resource is assigned to.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '111111111111', 'opentelemetry'
|
||||
CloudAccountIDKey = attribute.Key("cloud.account.id")
|
||||
// The geographical region the resource is running.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'us-central1', 'us-east-1'
|
||||
// Note: Refer to your provider's docs to see the available regions, for example
|
||||
// [Alibaba Cloud regions](https://www.alibabacloud.com/help/doc-
|
||||
// detail/40654.htm), [AWS regions](https://aws.amazon.com/about-aws/global-
|
||||
// infrastructure/regions_az/), [Azure regions](https://azure.microsoft.com/en-
|
||||
// us/global-infrastructure/geographies/), [Google Cloud
|
||||
// regions](https://cloud.google.com/about/locations), or [Tencent Cloud
|
||||
// regions](https://intl.cloud.tencent.com/document/product/213/6091).
|
||||
CloudRegionKey = attribute.Key("cloud.region")
|
||||
// Cloud regions often have multiple, isolated locations known as zones to
|
||||
// increase availability. Availability zone represents the zone where the resource
|
||||
// is running.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'us-east-1c'
|
||||
// Note: Availability zones are called "zones" on Alibaba Cloud and Google Cloud.
|
||||
CloudAvailabilityZoneKey = attribute.Key("cloud.availability_zone")
|
||||
// The cloud platform in use.
|
||||
//
|
||||
// Type: Enum
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Note: The prefix of the service SHOULD match the one specified in
|
||||
// `cloud.provider`.
|
||||
CloudPlatformKey = attribute.Key("cloud.platform")
|
||||
)
|
||||
|
||||
var (
|
||||
// Alibaba Cloud
|
||||
CloudProviderAlibabaCloud = CloudProviderKey.String("alibaba_cloud")
|
||||
// Amazon Web Services
|
||||
CloudProviderAWS = CloudProviderKey.String("aws")
|
||||
// Microsoft Azure
|
||||
CloudProviderAzure = CloudProviderKey.String("azure")
|
||||
// Google Cloud Platform
|
||||
CloudProviderGCP = CloudProviderKey.String("gcp")
|
||||
// Tencent Cloud
|
||||
CloudProviderTencentCloud = CloudProviderKey.String("tencent_cloud")
|
||||
)
|
||||
|
||||
var (
|
||||
// Alibaba Cloud Elastic Compute Service
|
||||
CloudPlatformAlibabaCloudECS = CloudPlatformKey.String("alibaba_cloud_ecs")
|
||||
// Alibaba Cloud Function Compute
|
||||
CloudPlatformAlibabaCloudFc = CloudPlatformKey.String("alibaba_cloud_fc")
|
||||
// AWS Elastic Compute Cloud
|
||||
CloudPlatformAWSEC2 = CloudPlatformKey.String("aws_ec2")
|
||||
// AWS Elastic Container Service
|
||||
CloudPlatformAWSECS = CloudPlatformKey.String("aws_ecs")
|
||||
// AWS Elastic Kubernetes Service
|
||||
CloudPlatformAWSEKS = CloudPlatformKey.String("aws_eks")
|
||||
// AWS Lambda
|
||||
CloudPlatformAWSLambda = CloudPlatformKey.String("aws_lambda")
|
||||
// AWS Elastic Beanstalk
|
||||
CloudPlatformAWSElasticBeanstalk = CloudPlatformKey.String("aws_elastic_beanstalk")
|
||||
// AWS App Runner
|
||||
CloudPlatformAWSAppRunner = CloudPlatformKey.String("aws_app_runner")
|
||||
// Azure Virtual Machines
|
||||
CloudPlatformAzureVM = CloudPlatformKey.String("azure_vm")
|
||||
// Azure Container Instances
|
||||
CloudPlatformAzureContainerInstances = CloudPlatformKey.String("azure_container_instances")
|
||||
// Azure Kubernetes Service
|
||||
CloudPlatformAzureAKS = CloudPlatformKey.String("azure_aks")
|
||||
// Azure Functions
|
||||
CloudPlatformAzureFunctions = CloudPlatformKey.String("azure_functions")
|
||||
// Azure App Service
|
||||
CloudPlatformAzureAppService = CloudPlatformKey.String("azure_app_service")
|
||||
// Google Cloud Compute Engine (GCE)
|
||||
CloudPlatformGCPComputeEngine = CloudPlatformKey.String("gcp_compute_engine")
|
||||
// Google Cloud Run
|
||||
CloudPlatformGCPCloudRun = CloudPlatformKey.String("gcp_cloud_run")
|
||||
// Google Cloud Kubernetes Engine (GKE)
|
||||
CloudPlatformGCPKubernetesEngine = CloudPlatformKey.String("gcp_kubernetes_engine")
|
||||
// Google Cloud Functions (GCF)
|
||||
CloudPlatformGCPCloudFunctions = CloudPlatformKey.String("gcp_cloud_functions")
|
||||
// Google Cloud App Engine (GAE)
|
||||
CloudPlatformGCPAppEngine = CloudPlatformKey.String("gcp_app_engine")
|
||||
// Tencent Cloud Cloud Virtual Machine (CVM)
|
||||
CloudPlatformTencentCloudCvm = CloudPlatformKey.String("tencent_cloud_cvm")
|
||||
// Tencent Cloud Elastic Kubernetes Service (EKS)
|
||||
CloudPlatformTencentCloudEKS = CloudPlatformKey.String("tencent_cloud_eks")
|
||||
// Tencent Cloud Serverless Cloud Function (SCF)
|
||||
CloudPlatformTencentCloudScf = CloudPlatformKey.String("tencent_cloud_scf")
|
||||
)
|
||||
|
||||
// Resources used by AWS Elastic Container Service (ECS).
|
||||
const (
|
||||
// The Amazon Resource Name (ARN) of an [ECS container instance](https://docs.aws.
|
||||
// amazon.com/AmazonECS/latest/developerguide/ECS_instances.html).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:ecs:us-
|
||||
// west-1:123456789123:container/32624152-9086-4f0e-acae-1a75b14fe4d9'
|
||||
AWSECSContainerARNKey = attribute.Key("aws.ecs.container.arn")
|
||||
// The ARN of an [ECS cluster](https://docs.aws.amazon.com/AmazonECS/latest/develo
|
||||
// perguide/clusters.html).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:ecs:us-west-2:123456789123:cluster/my-cluster'
|
||||
AWSECSClusterARNKey = attribute.Key("aws.ecs.cluster.arn")
|
||||
// The [launch type](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/l
|
||||
// aunch_types.html) for an ECS task.
|
||||
//
|
||||
// Type: Enum
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
AWSECSLaunchtypeKey = attribute.Key("aws.ecs.launchtype")
|
||||
// The ARN of an [ECS task definition](https://docs.aws.amazon.com/AmazonECS/lates
|
||||
// t/developerguide/task_definitions.html).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:ecs:us-
|
||||
// west-1:123456789123:task/10838bed-421f-43ef-870a-f43feacbbb5b'
|
||||
AWSECSTaskARNKey = attribute.Key("aws.ecs.task.arn")
|
||||
// The task definition family this task definition is a member of.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry-family'
|
||||
AWSECSTaskFamilyKey = attribute.Key("aws.ecs.task.family")
|
||||
// The revision for this task definition.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '8', '26'
|
||||
AWSECSTaskRevisionKey = attribute.Key("aws.ecs.task.revision")
|
||||
)
|
||||
|
||||
var (
|
||||
// ec2
|
||||
AWSECSLaunchtypeEC2 = AWSECSLaunchtypeKey.String("ec2")
|
||||
// fargate
|
||||
AWSECSLaunchtypeFargate = AWSECSLaunchtypeKey.String("fargate")
|
||||
)
|
||||
|
||||
// Resources used by AWS Elastic Kubernetes Service (EKS).
|
||||
const (
|
||||
// The ARN of an EKS cluster.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:ecs:us-west-2:123456789123:cluster/my-cluster'
|
||||
AWSEKSClusterARNKey = attribute.Key("aws.eks.cluster.arn")
|
||||
)
|
||||
|
||||
// Resources specific to Amazon Web Services.
|
||||
const (
|
||||
// The name(s) of the AWS log group(s) an application is writing to.
|
||||
//
|
||||
// Type: string[]
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '/aws/lambda/my-function', 'opentelemetry-service'
|
||||
// Note: Multiple log groups must be supported for cases like multi-container
|
||||
// applications, where a single application has sidecar containers, and each write
|
||||
// to their own log group.
|
||||
AWSLogGroupNamesKey = attribute.Key("aws.log.group.names")
|
||||
// The Amazon Resource Name(s) (ARN) of the AWS log group(s).
|
||||
//
|
||||
// Type: string[]
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:logs:us-west-1:123456789012:log-group:/aws/my/group:*'
|
||||
// Note: See the [log group ARN format
|
||||
// documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/iam-
|
||||
// access-control-overview-cwl.html#CWL_ARN_Format).
|
||||
AWSLogGroupARNsKey = attribute.Key("aws.log.group.arns")
|
||||
// The name(s) of the AWS log stream(s) an application is writing to.
|
||||
//
|
||||
// Type: string[]
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'logs/main/10838bed-421f-43ef-870a-f43feacbbb5b'
|
||||
AWSLogStreamNamesKey = attribute.Key("aws.log.stream.names")
|
||||
// The ARN(s) of the AWS log stream(s).
|
||||
//
|
||||
// Type: string[]
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:logs:us-west-1:123456789012:log-group:/aws/my/group:log-
|
||||
// stream:logs/main/10838bed-421f-43ef-870a-f43feacbbb5b'
|
||||
// Note: See the [log stream ARN format
|
||||
// documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/iam-
|
||||
// access-control-overview-cwl.html#CWL_ARN_Format). One log group can contain
|
||||
// several log streams, so these ARNs necessarily identify both a log group and a
|
||||
// log stream.
|
||||
AWSLogStreamARNsKey = attribute.Key("aws.log.stream.arns")
|
||||
)
|
||||
|
||||
// A container instance.
|
||||
const (
|
||||
// Container name used by container runtime.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry-autoconf'
|
||||
ContainerNameKey = attribute.Key("container.name")
|
||||
// Container ID. Usually a UUID, as for example used to [identify Docker
|
||||
// containers](https://docs.docker.com/engine/reference/run/#container-
|
||||
// identification). The UUID might be abbreviated.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'a3bf90e006b2'
|
||||
ContainerIDKey = attribute.Key("container.id")
|
||||
// The container runtime managing this container.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'docker', 'containerd', 'rkt'
|
||||
ContainerRuntimeKey = attribute.Key("container.runtime")
|
||||
// Name of the image the container was built on.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'gcr.io/opentelemetry/operator'
|
||||
ContainerImageNameKey = attribute.Key("container.image.name")
|
||||
// Container image tag.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '0.1'
|
||||
ContainerImageTagKey = attribute.Key("container.image.tag")
|
||||
)
|
||||
|
||||
// The software deployment.
|
||||
const (
|
||||
// Name of the [deployment
|
||||
// environment](https://en.wikipedia.org/wiki/Deployment_environment) (aka
|
||||
// deployment tier).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'staging', 'production'
|
||||
DeploymentEnvironmentKey = attribute.Key("deployment.environment")
|
||||
)
|
||||
|
||||
// The device on which the process represented by this resource is running.
|
||||
const (
|
||||
// A unique identifier representing the device
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '2ab2916d-a51f-4ac8-80ee-45ac31a28092'
|
||||
// Note: The device identifier MUST only be defined using the values outlined
|
||||
// below. This value is not an advertising identifier and MUST NOT be used as
|
||||
// such. On iOS (Swift or Objective-C), this value MUST be equal to the [vendor id
|
||||
// entifier](https://developer.apple.com/documentation/uikit/uidevice/1620059-iden
|
||||
// tifierforvendor). On Android (Java or Kotlin), this value MUST be equal to the
|
||||
// Firebase Installation ID or a globally unique UUID which is persisted across
|
||||
// sessions in your application. More information can be found
|
||||
// [here](https://developer.android.com/training/articles/user-data-ids) on best
|
||||
// practices and exact implementation details. Caution should be taken when
|
||||
// storing personal data or anything which can identify a user. GDPR and data
|
||||
// protection laws may apply, ensure you do your own due diligence.
|
||||
DeviceIDKey = attribute.Key("device.id")
|
||||
// The model identifier for the device
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'iPhone3,4', 'SM-G920F'
|
||||
// Note: It's recommended this value represents a machine readable version of the
|
||||
// model identifier rather than the market or consumer-friendly name of the
|
||||
// device.
|
||||
DeviceModelIdentifierKey = attribute.Key("device.model.identifier")
|
||||
// The marketing name for the device model
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'iPhone 6s Plus', 'Samsung Galaxy S6'
|
||||
// Note: It's recommended this value represents a human readable version of the
|
||||
// device model rather than a machine readable alternative.
|
||||
DeviceModelNameKey = attribute.Key("device.model.name")
|
||||
// The name of the device manufacturer
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'Apple', 'Samsung'
|
||||
// Note: The Android OS provides this field via
|
||||
// [Build](https://developer.android.com/reference/android/os/Build#MANUFACTURER).
|
||||
// iOS apps SHOULD hardcode the value `Apple`.
|
||||
DeviceManufacturerKey = attribute.Key("device.manufacturer")
|
||||
)
|
||||
|
||||
// A serverless instance.
|
||||
const (
|
||||
// The name of the single function that this runtime instance executes.
|
||||
//
|
||||
// Type: string
|
||||
// Required: Always
|
||||
// Stability: stable
|
||||
// Examples: 'my-function'
|
||||
// Note: This is the name of the function as configured/deployed on the FaaS
|
||||
// platform and is usually different from the name of the callback function (which
|
||||
// may be stored in the
|
||||
// [`code.namespace`/`code.function`](../../trace/semantic_conventions/span-
|
||||
// general.md#source-code-attributes) span attributes).
|
||||
FaaSNameKey = attribute.Key("faas.name")
|
||||
// The unique ID of the single function that this runtime instance executes.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'arn:aws:lambda:us-west-2:123456789012:function:my-function'
|
||||
// Note: Depending on the cloud provider, use:
|
||||
|
||||
// * **AWS Lambda:** The function
|
||||
// [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-
|
||||
// namespaces.html).
|
||||
// Take care not to use the "invoked ARN" directly but replace any
|
||||
// [alias suffix](https://docs.aws.amazon.com/lambda/latest/dg/configuration-
|
||||
// aliases.html) with the resolved function version, as the same runtime instance
|
||||
// may be invokable with multiple
|
||||
// different aliases.
|
||||
// * **GCP:** The [URI of the resource](https://cloud.google.com/iam/docs/full-
|
||||
// resource-names)
|
||||
// * **Azure:** The [Fully Qualified Resource ID](https://docs.microsoft.com/en-
|
||||
// us/rest/api/resources/resources/get-by-id).
|
||||
|
||||
// On some providers, it may not be possible to determine the full ID at startup,
|
||||
// which is why this field cannot be made required. For example, on AWS the
|
||||
// account ID
|
||||
// part of the ARN is not available without calling another AWS API
|
||||
// which may be deemed too slow for a short-running lambda function.
|
||||
// As an alternative, consider setting `faas.id` as a span attribute instead.
|
||||
FaaSIDKey = attribute.Key("faas.id")
|
||||
// The immutable version of the function being executed.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '26', 'pinkfroid-00002'
|
||||
// Note: Depending on the cloud provider and platform, use:
|
||||
|
||||
// * **AWS Lambda:** The [function
|
||||
// version](https://docs.aws.amazon.com/lambda/latest/dg/configuration-
|
||||
// versions.html)
|
||||
// (an integer represented as a decimal string).
|
||||
// * **Google Cloud Run:** The
|
||||
// [revision](https://cloud.google.com/run/docs/managing/revisions)
|
||||
// (i.e., the function name plus the revision suffix).
|
||||
// * **Google Cloud Functions:** The value of the
|
||||
// [`K_REVISION` environment
|
||||
// variable](https://cloud.google.com/functions/docs/env-
|
||||
// var#runtime_environment_variables_set_automatically).
|
||||
// * **Azure Functions:** Not applicable. Do not set this attribute.
|
||||
FaaSVersionKey = attribute.Key("faas.version")
|
||||
// The execution environment ID as a string, that will be potentially reused for
|
||||
// other invocations to the same function/function version.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '2021/06/28/[$LATEST]2f399eb14537447da05ab2a2e39309de'
|
||||
// Note: * **AWS Lambda:** Use the (full) log stream name.
|
||||
FaaSInstanceKey = attribute.Key("faas.instance")
|
||||
// The amount of memory available to the serverless function in MiB.
|
||||
//
|
||||
// Type: int
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 128
|
||||
// Note: It's recommended to set this attribute since e.g. too little memory can
|
||||
// easily stop a Java AWS Lambda function from working correctly. On AWS Lambda,
|
||||
// the environment variable `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` provides this
|
||||
// information.
|
||||
FaaSMaxMemoryKey = attribute.Key("faas.max_memory")
|
||||
)
|
||||
|
||||
// A host is defined as a general computing instance.
|
||||
const (
|
||||
// Unique host ID. For Cloud, this must be the instance_id assigned by the cloud
|
||||
// provider.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry-test'
|
||||
HostIDKey = attribute.Key("host.id")
|
||||
// Name of the host. On Unix systems, it may contain what the hostname command
|
||||
// returns, or the fully qualified hostname, or another name specified by the
|
||||
// user.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry-test'
|
||||
HostNameKey = attribute.Key("host.name")
|
||||
// Type of host. For Cloud, this must be the machine type.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'n1-standard-1'
|
||||
HostTypeKey = attribute.Key("host.type")
|
||||
// The CPU architecture the host system is running on.
|
||||
//
|
||||
// Type: Enum
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
HostArchKey = attribute.Key("host.arch")
|
||||
// Name of the VM image or OS install the host was instantiated from.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'infra-ami-eks-worker-node-7d4ec78312', 'CentOS-8-x86_64-1905'
|
||||
HostImageNameKey = attribute.Key("host.image.name")
|
||||
// VM image ID. For Cloud, this value is from the provider.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'ami-07b06b442921831e5'
|
||||
HostImageIDKey = attribute.Key("host.image.id")
|
||||
// The version string of the VM image as defined in [Version
|
||||
// Attributes](README.md#version-attributes).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '0.1'
|
||||
HostImageVersionKey = attribute.Key("host.image.version")
|
||||
)
|
||||
|
||||
var (
|
||||
// AMD64
|
||||
HostArchAMD64 = HostArchKey.String("amd64")
|
||||
// ARM32
|
||||
HostArchARM32 = HostArchKey.String("arm32")
|
||||
// ARM64
|
||||
HostArchARM64 = HostArchKey.String("arm64")
|
||||
// Itanium
|
||||
HostArchIA64 = HostArchKey.String("ia64")
|
||||
// 32-bit PowerPC
|
||||
HostArchPPC32 = HostArchKey.String("ppc32")
|
||||
// 64-bit PowerPC
|
||||
HostArchPPC64 = HostArchKey.String("ppc64")
|
||||
// IBM z/Architecture
|
||||
HostArchS390x = HostArchKey.String("s390x")
|
||||
// 32-bit x86
|
||||
HostArchX86 = HostArchKey.String("x86")
|
||||
)
|
||||
|
||||
// A Kubernetes Cluster.
|
||||
const (
|
||||
// The name of the cluster.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry-cluster'
|
||||
K8SClusterNameKey = attribute.Key("k8s.cluster.name")
|
||||
)
|
||||
|
||||
// A Kubernetes Node object.
|
||||
const (
|
||||
// The name of the Node.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'node-1'
|
||||
K8SNodeNameKey = attribute.Key("k8s.node.name")
|
||||
// The UID of the Node.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '1eb3a0c6-0477-4080-a9cb-0cb7db65c6a2'
|
||||
K8SNodeUIDKey = attribute.Key("k8s.node.uid")
|
||||
)
|
||||
|
||||
// A Kubernetes Namespace.
|
||||
const (
|
||||
// The name of the namespace that the pod is running in.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'default'
|
||||
K8SNamespaceNameKey = attribute.Key("k8s.namespace.name")
|
||||
)
|
||||
|
||||
// A Kubernetes Pod object.
|
||||
const (
|
||||
// The UID of the Pod.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SPodUIDKey = attribute.Key("k8s.pod.uid")
|
||||
// The name of the Pod.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry-pod-autoconf'
|
||||
K8SPodNameKey = attribute.Key("k8s.pod.name")
|
||||
)
|
||||
|
||||
// A container in a [PodTemplate](https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates).
|
||||
const (
|
||||
// The name of the Container from Pod specification, must be unique within a Pod.
|
||||
// Container runtime usually uses different globally unique name
|
||||
// (`container.name`).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'redis'
|
||||
K8SContainerNameKey = attribute.Key("k8s.container.name")
|
||||
// Number of times the container was restarted. This attribute can be used to
|
||||
// identify a particular container (running or stopped) within a container spec.
|
||||
//
|
||||
// Type: int
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 0, 2
|
||||
K8SContainerRestartCountKey = attribute.Key("k8s.container.restart_count")
|
||||
)
|
||||
|
||||
// A Kubernetes ReplicaSet object.
|
||||
const (
|
||||
// The UID of the ReplicaSet.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SReplicaSetUIDKey = attribute.Key("k8s.replicaset.uid")
|
||||
// The name of the ReplicaSet.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
K8SReplicaSetNameKey = attribute.Key("k8s.replicaset.name")
|
||||
)
|
||||
|
||||
// A Kubernetes Deployment object.
|
||||
const (
|
||||
// The UID of the Deployment.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SDeploymentUIDKey = attribute.Key("k8s.deployment.uid")
|
||||
// The name of the Deployment.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
K8SDeploymentNameKey = attribute.Key("k8s.deployment.name")
|
||||
)
|
||||
|
||||
// A Kubernetes StatefulSet object.
|
||||
const (
|
||||
// The UID of the StatefulSet.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SStatefulSetUIDKey = attribute.Key("k8s.statefulset.uid")
|
||||
// The name of the StatefulSet.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
K8SStatefulSetNameKey = attribute.Key("k8s.statefulset.name")
|
||||
)
|
||||
|
||||
// A Kubernetes DaemonSet object.
|
||||
const (
|
||||
// The UID of the DaemonSet.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SDaemonSetUIDKey = attribute.Key("k8s.daemonset.uid")
|
||||
// The name of the DaemonSet.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
K8SDaemonSetNameKey = attribute.Key("k8s.daemonset.name")
|
||||
)
|
||||
|
||||
// A Kubernetes Job object.
|
||||
const (
|
||||
// The UID of the Job.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SJobUIDKey = attribute.Key("k8s.job.uid")
|
||||
// The name of the Job.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
K8SJobNameKey = attribute.Key("k8s.job.name")
|
||||
)
|
||||
|
||||
// A Kubernetes CronJob object.
|
||||
const (
|
||||
// The UID of the CronJob.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '275ecb36-5aa8-4c2a-9c47-d8bb681b9aff'
|
||||
K8SCronJobUIDKey = attribute.Key("k8s.cronjob.uid")
|
||||
// The name of the CronJob.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
K8SCronJobNameKey = attribute.Key("k8s.cronjob.name")
|
||||
)
|
||||
|
||||
// The operating system (OS) on which the process represented by this resource is running.
|
||||
const (
|
||||
// The operating system type.
|
||||
//
|
||||
// Type: Enum
|
||||
// Required: Always
|
||||
// Stability: stable
|
||||
OSTypeKey = attribute.Key("os.type")
|
||||
// Human readable (not intended to be parsed) OS version information, like e.g.
|
||||
// reported by `ver` or `lsb_release -a` commands.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'Microsoft Windows [Version 10.0.18363.778]', 'Ubuntu 18.04.1 LTS'
|
||||
OSDescriptionKey = attribute.Key("os.description")
|
||||
// Human readable operating system name.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'iOS', 'Android', 'Ubuntu'
|
||||
OSNameKey = attribute.Key("os.name")
|
||||
// The version string of the operating system as defined in [Version
|
||||
// Attributes](../../resource/semantic_conventions/README.md#version-attributes).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '14.2.1', '18.04.1'
|
||||
OSVersionKey = attribute.Key("os.version")
|
||||
)
|
||||
|
||||
var (
|
||||
// Microsoft Windows
|
||||
OSTypeWindows = OSTypeKey.String("windows")
|
||||
// Linux
|
||||
OSTypeLinux = OSTypeKey.String("linux")
|
||||
// Apple Darwin
|
||||
OSTypeDarwin = OSTypeKey.String("darwin")
|
||||
// FreeBSD
|
||||
OSTypeFreeBSD = OSTypeKey.String("freebsd")
|
||||
// NetBSD
|
||||
OSTypeNetBSD = OSTypeKey.String("netbsd")
|
||||
// OpenBSD
|
||||
OSTypeOpenBSD = OSTypeKey.String("openbsd")
|
||||
// DragonFly BSD
|
||||
OSTypeDragonflyBSD = OSTypeKey.String("dragonflybsd")
|
||||
// HP-UX (Hewlett Packard Unix)
|
||||
OSTypeHPUX = OSTypeKey.String("hpux")
|
||||
// AIX (Advanced Interactive eXecutive)
|
||||
OSTypeAIX = OSTypeKey.String("aix")
|
||||
// Oracle Solaris
|
||||
OSTypeSolaris = OSTypeKey.String("solaris")
|
||||
// IBM z/OS
|
||||
OSTypeZOS = OSTypeKey.String("z_os")
|
||||
)
|
||||
|
||||
// An operating system process.
|
||||
const (
|
||||
// Process identifier (PID).
|
||||
//
|
||||
// Type: int
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 1234
|
||||
ProcessPIDKey = attribute.Key("process.pid")
|
||||
// The name of the process executable. On Linux based systems, can be set to the
|
||||
// `Name` in `proc/[pid]/status`. On Windows, can be set to the base name of
|
||||
// `GetProcessImageFileNameW`.
|
||||
//
|
||||
// Type: string
|
||||
// Required: See below
|
||||
// Stability: stable
|
||||
// Examples: 'otelcol'
|
||||
ProcessExecutableNameKey = attribute.Key("process.executable.name")
|
||||
// The full path to the process executable. On Linux based systems, can be set to
|
||||
// the target of `proc/[pid]/exe`. On Windows, can be set to the result of
|
||||
// `GetProcessImageFileNameW`.
|
||||
//
|
||||
// Type: string
|
||||
// Required: See below
|
||||
// Stability: stable
|
||||
// Examples: '/usr/bin/cmd/otelcol'
|
||||
ProcessExecutablePathKey = attribute.Key("process.executable.path")
|
||||
// The command used to launch the process (i.e. the command name). On Linux based
|
||||
// systems, can be set to the zeroth string in `proc/[pid]/cmdline`. On Windows,
|
||||
// can be set to the first parameter extracted from `GetCommandLineW`.
|
||||
//
|
||||
// Type: string
|
||||
// Required: See below
|
||||
// Stability: stable
|
||||
// Examples: 'cmd/otelcol'
|
||||
ProcessCommandKey = attribute.Key("process.command")
|
||||
// The full command used to launch the process as a single string representing the
|
||||
// full command. On Windows, can be set to the result of `GetCommandLineW`. Do not
|
||||
// set this if you have to assemble it just for monitoring; use
|
||||
// `process.command_args` instead.
|
||||
//
|
||||
// Type: string
|
||||
// Required: See below
|
||||
// Stability: stable
|
||||
// Examples: 'C:\\cmd\\otecol --config="my directory\\config.yaml"'
|
||||
ProcessCommandLineKey = attribute.Key("process.command_line")
|
||||
// All the command arguments (including the command/executable itself) as received
|
||||
// by the process. On Linux-based systems (and some other Unixoid systems
|
||||
// supporting procfs), can be set according to the list of null-delimited strings
|
||||
// extracted from `proc/[pid]/cmdline`. For libc-based executables, this would be
|
||||
// the full argv vector passed to `main`.
|
||||
//
|
||||
// Type: string[]
|
||||
// Required: See below
|
||||
// Stability: stable
|
||||
// Examples: 'cmd/otecol', '--config=config.yaml'
|
||||
ProcessCommandArgsKey = attribute.Key("process.command_args")
|
||||
// The username of the user that owns the process.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'root'
|
||||
ProcessOwnerKey = attribute.Key("process.owner")
|
||||
)
|
||||
|
||||
// The single (language) runtime instance which is monitored.
|
||||
const (
|
||||
// The name of the runtime of this process. For compiled native binaries, this
|
||||
// SHOULD be the name of the compiler.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'OpenJDK Runtime Environment'
|
||||
ProcessRuntimeNameKey = attribute.Key("process.runtime.name")
|
||||
// The version of the runtime of this process, as returned by the runtime without
|
||||
// modification.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '14.0.2'
|
||||
ProcessRuntimeVersionKey = attribute.Key("process.runtime.version")
|
||||
// An additional description about the runtime of the process, for example a
|
||||
// specific vendor customization of the runtime environment.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'Eclipse OpenJ9 Eclipse OpenJ9 VM openj9-0.21.0'
|
||||
ProcessRuntimeDescriptionKey = attribute.Key("process.runtime.description")
|
||||
)
|
||||
|
||||
// A service instance.
|
||||
const (
|
||||
// Logical name of the service.
|
||||
//
|
||||
// Type: string
|
||||
// Required: Always
|
||||
// Stability: stable
|
||||
// Examples: 'shoppingcart'
|
||||
// Note: MUST be the same for all instances of horizontally scaled services. If
|
||||
// the value was not specified, SDKs MUST fallback to `unknown_service:`
|
||||
// concatenated with [`process.executable.name`](process.md#process), e.g.
|
||||
// `unknown_service:bash`. If `process.executable.name` is not available, the
|
||||
// value MUST be set to `unknown_service`.
|
||||
ServiceNameKey = attribute.Key("service.name")
|
||||
// A namespace for `service.name`.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'Shop'
|
||||
// Note: A string value having a meaning that helps to distinguish a group of
|
||||
// services, for example the team name that owns a group of services.
|
||||
// `service.name` is expected to be unique within the same namespace. If
|
||||
// `service.namespace` is not specified in the Resource then `service.name` is
|
||||
// expected to be unique for all services that have no explicit namespace defined
|
||||
// (so the empty/unspecified namespace is simply one more valid namespace). Zero-
|
||||
// length namespace string is assumed equal to unspecified namespace.
|
||||
ServiceNamespaceKey = attribute.Key("service.namespace")
|
||||
// The string ID of the service instance.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '627cc493-f310-47de-96bd-71410b7dec09'
|
||||
// Note: MUST be unique for each instance of the same
|
||||
// `service.namespace,service.name` pair (in other words
|
||||
// `service.namespace,service.name,service.instance.id` triplet MUST be globally
|
||||
// unique). The ID helps to distinguish instances of the same service that exist
|
||||
// at the same time (e.g. instances of a horizontally scaled service). It is
|
||||
// preferable for the ID to be persistent and stay the same for the lifetime of
|
||||
// the service instance, however it is acceptable that the ID is ephemeral and
|
||||
// changes during important lifetime events for the service (e.g. service
|
||||
// restarts). If the service has no inherent unique ID that can be used as the
|
||||
// value of this attribute it is recommended to generate a random Version 1 or
|
||||
// Version 4 RFC 4122 UUID (services aiming for reproducible UUIDs may also use
|
||||
// Version 5, see RFC 4122 for more recommendations).
|
||||
ServiceInstanceIDKey = attribute.Key("service.instance.id")
|
||||
// The version string of the service API or implementation.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '2.0.0'
|
||||
ServiceVersionKey = attribute.Key("service.version")
|
||||
)
|
||||
|
||||
// The telemetry SDK used to capture data recorded by the instrumentation libraries.
|
||||
const (
|
||||
// The name of the telemetry SDK as defined above.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'opentelemetry'
|
||||
TelemetrySDKNameKey = attribute.Key("telemetry.sdk.name")
|
||||
// The language of the telemetry SDK.
|
||||
//
|
||||
// Type: Enum
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
TelemetrySDKLanguageKey = attribute.Key("telemetry.sdk.language")
|
||||
// The version string of the telemetry SDK.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '1.2.3'
|
||||
TelemetrySDKVersionKey = attribute.Key("telemetry.sdk.version")
|
||||
// The version string of the auto instrumentation agent, if used.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '1.2.3'
|
||||
TelemetryAutoVersionKey = attribute.Key("telemetry.auto.version")
|
||||
)
|
||||
|
||||
var (
|
||||
// cpp
|
||||
TelemetrySDKLanguageCPP = TelemetrySDKLanguageKey.String("cpp")
|
||||
// dotnet
|
||||
TelemetrySDKLanguageDotnet = TelemetrySDKLanguageKey.String("dotnet")
|
||||
// erlang
|
||||
TelemetrySDKLanguageErlang = TelemetrySDKLanguageKey.String("erlang")
|
||||
// go
|
||||
TelemetrySDKLanguageGo = TelemetrySDKLanguageKey.String("go")
|
||||
// java
|
||||
TelemetrySDKLanguageJava = TelemetrySDKLanguageKey.String("java")
|
||||
// nodejs
|
||||
TelemetrySDKLanguageNodejs = TelemetrySDKLanguageKey.String("nodejs")
|
||||
// php
|
||||
TelemetrySDKLanguagePHP = TelemetrySDKLanguageKey.String("php")
|
||||
// python
|
||||
TelemetrySDKLanguagePython = TelemetrySDKLanguageKey.String("python")
|
||||
// ruby
|
||||
TelemetrySDKLanguageRuby = TelemetrySDKLanguageKey.String("ruby")
|
||||
// webjs
|
||||
TelemetrySDKLanguageWebjs = TelemetrySDKLanguageKey.String("webjs")
|
||||
// swift
|
||||
TelemetrySDKLanguageSwift = TelemetrySDKLanguageKey.String("swift")
|
||||
)
|
||||
|
||||
// Resource describing the packaged software running the application code. Web engines are typically executed using process.runtime.
|
||||
const (
|
||||
// The name of the web engine.
|
||||
//
|
||||
// Type: string
|
||||
// Required: Always
|
||||
// Stability: stable
|
||||
// Examples: 'WildFly'
|
||||
WebEngineNameKey = attribute.Key("webengine.name")
|
||||
// The version of the web engine.
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: '21.0.0'
|
||||
WebEngineVersionKey = attribute.Key("webengine.version")
|
||||
// Additional description of the web engine (e.g. detailed version and edition
|
||||
// information).
|
||||
//
|
||||
// Type: string
|
||||
// Required: No
|
||||
// Stability: stable
|
||||
// Examples: 'WildFly Full 21.0.0.Final (WildFly Core 13.0.1.Final) - 2.2.2.Final'
|
||||
WebEngineDescriptionKey = attribute.Key("webengine.description")
|
||||
)
|
||||
9
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/schema.go
generated
vendored
9
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/schema.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.10.0"
|
||||
|
||||
// SchemaURL is the schema URL that matches the version of the semantic conventions
|
||||
// that this package defines. Semconv packages starting from v1.4.0 must declare
|
||||
// non-empty schema URL in the form https://opentelemetry.io/schemas/<version>
|
||||
const SchemaURL = "https://opentelemetry.io/schemas/1.10.0"
|
||||
1689
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/trace.go
generated
vendored
1689
vendor/go.opentelemetry.io/otel/semconv/v1.10.0/trace.go
generated
vendored
File diff suppressed because it is too large
Load Diff
18
vendor/golang.org/x/crypto/argon2/argon2.go
generated
vendored
18
vendor/golang.org/x/crypto/argon2/argon2.go
generated
vendored
@@ -6,7 +6,7 @@
|
||||
// Argon2 was selected as the winner of the Password Hashing Competition and can
|
||||
// be used to derive cryptographic keys from passwords.
|
||||
//
|
||||
// For a detailed specification of Argon2 see [1].
|
||||
// For a detailed specification of Argon2 see [argon2-specs.pdf].
|
||||
//
|
||||
// If you aren't sure which function you need, use Argon2id (IDKey) and
|
||||
// the parameter recommendations for your scenario.
|
||||
@@ -17,7 +17,7 @@
|
||||
// It uses data-independent memory access, which is preferred for password
|
||||
// hashing and password-based key derivation. Argon2i requires more passes over
|
||||
// memory than Argon2id to protect from trade-off attacks. The recommended
|
||||
// parameters (taken from [2]) for non-interactive operations are time=3 and to
|
||||
// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to
|
||||
// use the maximum available memory.
|
||||
//
|
||||
// # Argon2id
|
||||
@@ -27,11 +27,11 @@
|
||||
// half of the first iteration over the memory and data-dependent memory access
|
||||
// for the rest. Argon2id is side-channel resistant and provides better brute-
|
||||
// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
|
||||
// parameters for non-interactive operations (taken from [2]) are time=1 and to
|
||||
// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to
|
||||
// use the maximum available memory.
|
||||
//
|
||||
// [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
// [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3
|
||||
// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
package argon2
|
||||
|
||||
import (
|
||||
@@ -59,7 +59,7 @@ const (
|
||||
//
|
||||
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
|
||||
//
|
||||
// The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number.
|
||||
// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number.
|
||||
// If using that amount of memory (32 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
//
|
||||
@@ -69,6 +69,8 @@ const (
|
||||
// adjusted to the number of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
//
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
@@ -83,7 +85,7 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
|
||||
//
|
||||
// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
|
||||
//
|
||||
// The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number.
|
||||
// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number.
|
||||
// If using that amount of memory (64 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
//
|
||||
@@ -93,6 +95,8 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3
|
||||
// adjusted to the numbers of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
//
|
||||
// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3
|
||||
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
generated
vendored
2
vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
generated
vendored
@@ -29,7 +29,7 @@ loop:
|
||||
MOVD $NUM_ROUNDS, R21
|
||||
VLD1 (R11), [V30.S4, V31.S4]
|
||||
|
||||
// load contants
|
||||
// load constants
|
||||
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
|
||||
WORD $0x4D60E940
|
||||
|
||||
|
||||
10
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
10
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
@@ -56,7 +56,10 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
@@ -73,7 +76,10 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
|
||||
10
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
10
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
@@ -31,7 +31,10 @@ func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []b
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
|
||||
var polyKey [32]byte
|
||||
@@ -67,7 +70,10 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
|
||||
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if alias.AnyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !p.Verify(tag) {
|
||||
for i := range out {
|
||||
|
||||
66
vendor/golang.org/x/crypto/sha3/doc.go
generated
vendored
66
vendor/golang.org/x/crypto/sha3/doc.go
generated
vendored
@@ -1,66 +0,0 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package sha3 implements the SHA-3 fixed-output-length hash functions and
|
||||
// the SHAKE variable-output-length hash functions defined by FIPS-202.
|
||||
//
|
||||
// All types in this package also implement [encoding.BinaryMarshaler],
|
||||
// [encoding.BinaryAppender] and [encoding.BinaryUnmarshaler] to marshal and
|
||||
// unmarshal the internal state of the hash.
|
||||
//
|
||||
// Both types of hash function use the "sponge" construction and the Keccak
|
||||
// permutation. For a detailed specification see http://keccak.noekeon.org/
|
||||
//
|
||||
// # Guidance
|
||||
//
|
||||
// If you aren't sure what function you need, use SHAKE256 with at least 64
|
||||
// bytes of output. The SHAKE instances are faster than the SHA3 instances;
|
||||
// the latter have to allocate memory to conform to the hash.Hash interface.
|
||||
//
|
||||
// If you need a secret-key MAC (message authentication code), prepend the
|
||||
// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
|
||||
// output.
|
||||
//
|
||||
// # Security strengths
|
||||
//
|
||||
// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
|
||||
// strength against preimage attacks of x bits. Since they only produce "x"
|
||||
// bits of output, their collision-resistance is only "x/2" bits.
|
||||
//
|
||||
// The SHAKE-256 and -128 functions have a generic security strength of 256 and
|
||||
// 128 bits against all attacks, provided that at least 2x bits of their output
|
||||
// is used. Requesting more than 64 or 32 bytes of output, respectively, does
|
||||
// not increase the collision-resistance of the SHAKE functions.
|
||||
//
|
||||
// # The sponge construction
|
||||
//
|
||||
// A sponge builds a pseudo-random function from a public pseudo-random
|
||||
// permutation, by applying the permutation to a state of "rate + capacity"
|
||||
// bytes, but hiding "capacity" of the bytes.
|
||||
//
|
||||
// A sponge starts out with a zero state. To hash an input using a sponge, up
|
||||
// to "rate" bytes of the input are XORed into the sponge's state. The sponge
|
||||
// is then "full" and the permutation is applied to "empty" it. This process is
|
||||
// repeated until all the input has been "absorbed". The input is then padded.
|
||||
// The digest is "squeezed" from the sponge in the same way, except that output
|
||||
// is copied out instead of input being XORed in.
|
||||
//
|
||||
// A sponge is parameterized by its generic security strength, which is equal
|
||||
// to half its capacity; capacity + rate is equal to the permutation's width.
|
||||
// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
|
||||
// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
|
||||
//
|
||||
// # Recommendations
|
||||
//
|
||||
// The SHAKE functions are recommended for most new uses. They can produce
|
||||
// output of arbitrary length. SHAKE256, with an output length of at least
|
||||
// 64 bytes, provides 256-bit security against all attacks. The Keccak team
|
||||
// recommends it for most applications upgrading from SHA2-512. (NIST chose a
|
||||
// much stronger, but much slower, sponge instance for SHA3-512.)
|
||||
//
|
||||
// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
|
||||
// They produce output of the same length, with the same security strengths
|
||||
// against all attacks. This means, in particular, that SHA3-256 only has
|
||||
// 128-bit collision resistance, because its output length is 32 bytes.
|
||||
package sha3
|
||||
133
vendor/golang.org/x/crypto/sha3/hashes.go
generated
vendored
133
vendor/golang.org/x/crypto/sha3/hashes.go
generated
vendored
@@ -2,127 +2,94 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package sha3 implements the SHA-3 hash algorithms and the SHAKE extendable
|
||||
// output functions defined in FIPS 202.
|
||||
//
|
||||
// Most of this package is a wrapper around the crypto/sha3 package in the
|
||||
// standard library. The only exception is the legacy Keccak hash functions.
|
||||
package sha3
|
||||
|
||||
// This file provides functions for creating instances of the SHA-3
|
||||
// and SHAKE hash functions, as well as utility functions for hashing
|
||||
// bytes.
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/sha3"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// New224 creates a new SHA3-224 hash.
|
||||
// Its generic security strength is 224 bits against preimage attacks,
|
||||
// and 112 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New224] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New224() hash.Hash {
|
||||
return new224()
|
||||
return sha3.New224()
|
||||
}
|
||||
|
||||
// New256 creates a new SHA3-256 hash.
|
||||
// Its generic security strength is 256 bits against preimage attacks,
|
||||
// and 128 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New256] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New256() hash.Hash {
|
||||
return new256()
|
||||
return sha3.New256()
|
||||
}
|
||||
|
||||
// New384 creates a new SHA3-384 hash.
|
||||
// Its generic security strength is 384 bits against preimage attacks,
|
||||
// and 192 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New384] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New384() hash.Hash {
|
||||
return new384()
|
||||
return sha3.New384()
|
||||
}
|
||||
|
||||
// New512 creates a new SHA3-512 hash.
|
||||
// Its generic security strength is 512 bits against preimage attacks,
|
||||
// and 256 bits against collision attacks.
|
||||
//
|
||||
// It is a wrapper for the [sha3.New512] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func New512() hash.Hash {
|
||||
return new512()
|
||||
}
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.SHA3_224, New224)
|
||||
crypto.RegisterHash(crypto.SHA3_256, New256)
|
||||
crypto.RegisterHash(crypto.SHA3_384, New384)
|
||||
crypto.RegisterHash(crypto.SHA3_512, New512)
|
||||
}
|
||||
|
||||
const (
|
||||
dsbyteSHA3 = 0b00000110
|
||||
dsbyteKeccak = 0b00000001
|
||||
dsbyteShake = 0b00011111
|
||||
dsbyteCShake = 0b00000100
|
||||
|
||||
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
|
||||
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
|
||||
rateK256 = (1600 - 256) / 8
|
||||
rateK448 = (1600 - 448) / 8
|
||||
rateK512 = (1600 - 512) / 8
|
||||
rateK768 = (1600 - 768) / 8
|
||||
rateK1024 = (1600 - 1024) / 8
|
||||
)
|
||||
|
||||
func new224Generic() *state {
|
||||
return &state{rate: rateK448, outputLen: 28, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
func new256Generic() *state {
|
||||
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
func new384Generic() *state {
|
||||
return &state{rate: rateK768, outputLen: 48, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
func new512Generic() *state {
|
||||
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteSHA3}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak256 creates a new Keccak-256 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New256 instead.
|
||||
func NewLegacyKeccak256() hash.Hash {
|
||||
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak512 creates a new Keccak-512 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New512 instead.
|
||||
func NewLegacyKeccak512() hash.Hash {
|
||||
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
|
||||
return sha3.New512()
|
||||
}
|
||||
|
||||
// Sum224 returns the SHA3-224 digest of the data.
|
||||
func Sum224(data []byte) (digest [28]byte) {
|
||||
h := New224()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum224] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum224(data []byte) [28]byte {
|
||||
return sha3.Sum224(data)
|
||||
}
|
||||
|
||||
// Sum256 returns the SHA3-256 digest of the data.
|
||||
func Sum256(data []byte) (digest [32]byte) {
|
||||
h := New256()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum256] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum256(data []byte) [32]byte {
|
||||
return sha3.Sum256(data)
|
||||
}
|
||||
|
||||
// Sum384 returns the SHA3-384 digest of the data.
|
||||
func Sum384(data []byte) (digest [48]byte) {
|
||||
h := New384()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum384] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum384(data []byte) [48]byte {
|
||||
return sha3.Sum384(data)
|
||||
}
|
||||
|
||||
// Sum512 returns the SHA3-512 digest of the data.
|
||||
func Sum512(data []byte) (digest [64]byte) {
|
||||
h := New512()
|
||||
h.Write(data)
|
||||
h.Sum(digest[:0])
|
||||
return
|
||||
//
|
||||
// It is a wrapper for the [sha3.Sum512] function in the standard library.
|
||||
//
|
||||
//go:fix inline
|
||||
func Sum512(data []byte) [64]byte {
|
||||
return sha3.Sum512(data)
|
||||
}
|
||||
|
||||
23
vendor/golang.org/x/crypto/sha3/hashes_noasm.go
generated
vendored
23
vendor/golang.org/x/crypto/sha3/hashes_noasm.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !gc || purego || !s390x
|
||||
|
||||
package sha3
|
||||
|
||||
func new224() *state {
|
||||
return new224Generic()
|
||||
}
|
||||
|
||||
func new256() *state {
|
||||
return new256Generic()
|
||||
}
|
||||
|
||||
func new384() *state {
|
||||
return new384Generic()
|
||||
}
|
||||
|
||||
func new512() *state {
|
||||
return new512Generic()
|
||||
}
|
||||
13
vendor/golang.org/x/crypto/sha3/keccakf_amd64.go
generated
vendored
13
vendor/golang.org/x/crypto/sha3/keccakf_amd64.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build amd64 && !purego && gc
|
||||
|
||||
package sha3
|
||||
|
||||
// This function is implemented in keccakf_amd64.s.
|
||||
|
||||
//go:noescape
|
||||
|
||||
func keccakF1600(a *[25]uint64)
|
||||
5419
vendor/golang.org/x/crypto/sha3/keccakf_amd64.s
generated
vendored
5419
vendor/golang.org/x/crypto/sha3/keccakf_amd64.s
generated
vendored
File diff suppressed because it is too large
Load Diff
49
vendor/golang.org/x/crypto/sha3/sha3.go → vendor/golang.org/x/crypto/sha3/legacy_hash.go
generated
vendored
49
vendor/golang.org/x/crypto/sha3/sha3.go → vendor/golang.org/x/crypto/sha3/legacy_hash.go
generated
vendored
@@ -4,15 +4,46 @@
|
||||
|
||||
package sha3
|
||||
|
||||
// This implementation is only used for NewLegacyKeccak256 and
|
||||
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
|
||||
// All other functions in this package are wrappers around crypto/sha3.
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
const (
|
||||
dsbyteKeccak = 0b00000001
|
||||
|
||||
// rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
|
||||
// bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
|
||||
rateK256 = (1600 - 256) / 8
|
||||
rateK512 = (1600 - 512) / 8
|
||||
rateK1024 = (1600 - 1024) / 8
|
||||
)
|
||||
|
||||
// NewLegacyKeccak256 creates a new Keccak-256 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New256 instead.
|
||||
func NewLegacyKeccak256() hash.Hash {
|
||||
return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
|
||||
}
|
||||
|
||||
// NewLegacyKeccak512 creates a new Keccak-512 hash.
|
||||
//
|
||||
// Only use this function if you require compatibility with an existing cryptosystem
|
||||
// that uses non-standard padding. All other users should use New512 instead.
|
||||
func NewLegacyKeccak512() hash.Hash {
|
||||
return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
|
||||
}
|
||||
|
||||
// spongeDirection indicates the direction bytes are flowing through the sponge.
|
||||
type spongeDirection int
|
||||
|
||||
@@ -173,12 +204,9 @@ func (d *state) Sum(in []byte) []byte {
|
||||
}
|
||||
|
||||
const (
|
||||
magicSHA3 = "sha\x08"
|
||||
magicShake = "sha\x09"
|
||||
magicCShake = "sha\x0a"
|
||||
magicKeccak = "sha\x0b"
|
||||
// magic || rate || main state || n || sponge direction
|
||||
marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1
|
||||
marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1
|
||||
)
|
||||
|
||||
func (d *state) MarshalBinary() ([]byte, error) {
|
||||
@@ -187,12 +215,6 @@ func (d *state) MarshalBinary() ([]byte, error) {
|
||||
|
||||
func (d *state) AppendBinary(b []byte) ([]byte, error) {
|
||||
switch d.dsbyte {
|
||||
case dsbyteSHA3:
|
||||
b = append(b, magicSHA3...)
|
||||
case dsbyteShake:
|
||||
b = append(b, magicShake...)
|
||||
case dsbyteCShake:
|
||||
b = append(b, magicCShake...)
|
||||
case dsbyteKeccak:
|
||||
b = append(b, magicKeccak...)
|
||||
default:
|
||||
@@ -210,12 +232,9 @@ func (d *state) UnmarshalBinary(b []byte) error {
|
||||
return errors.New("sha3: invalid hash state")
|
||||
}
|
||||
|
||||
magic := string(b[:len(magicSHA3)])
|
||||
b = b[len(magicSHA3):]
|
||||
magic := string(b[:len(magicKeccak)])
|
||||
b = b[len(magicKeccak):]
|
||||
switch {
|
||||
case magic == magicSHA3 && d.dsbyte == dsbyteSHA3:
|
||||
case magic == magicShake && d.dsbyte == dsbyteShake:
|
||||
case magic == magicCShake && d.dsbyte == dsbyteCShake:
|
||||
case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
|
||||
default:
|
||||
return errors.New("sha3: invalid hash state identifier")
|
||||
@@ -2,10 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || purego || !gc
|
||||
|
||||
package sha3
|
||||
|
||||
// This implementation is only used for NewLegacyKeccak256 and
|
||||
// NewLegacyKeccak512, which are not implemented by crypto/sha3.
|
||||
// All other functions in this package are wrappers around crypto/sha3.
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// rc stores the round constants for use in the ι step.
|
||||
303
vendor/golang.org/x/crypto/sha3/sha3_s390x.go
generated
vendored
303
vendor/golang.org/x/crypto/sha3/sha3_s390x.go
generated
vendored
@@ -1,303 +0,0 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
|
||||
package sha3
|
||||
|
||||
// This file contains code for using the 'compute intermediate
|
||||
// message digest' (KIMD) and 'compute last message digest' (KLMD)
|
||||
// instructions to compute SHA-3 and SHAKE hashes on IBM Z.
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
// codes represent 7-bit KIMD/KLMD function codes as defined in
|
||||
// the Principles of Operation.
|
||||
type code uint64
|
||||
|
||||
const (
|
||||
// function codes for KIMD/KLMD
|
||||
sha3_224 code = 32
|
||||
sha3_256 = 33
|
||||
sha3_384 = 34
|
||||
sha3_512 = 35
|
||||
shake_128 = 36
|
||||
shake_256 = 37
|
||||
nopad = 0x100
|
||||
)
|
||||
|
||||
// kimd is a wrapper for the 'compute intermediate message digest' instruction.
|
||||
// src must be a multiple of the rate for the given function code.
|
||||
//
|
||||
//go:noescape
|
||||
func kimd(function code, chain *[200]byte, src []byte)
|
||||
|
||||
// klmd is a wrapper for the 'compute last message digest' instruction.
|
||||
// src padding is handled by the instruction.
|
||||
//
|
||||
//go:noescape
|
||||
func klmd(function code, chain *[200]byte, dst, src []byte)
|
||||
|
||||
type asmState struct {
|
||||
a [200]byte // 1600 bit state
|
||||
buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
|
||||
rate int // equivalent to block size
|
||||
storage [3072]byte // underlying storage for buf
|
||||
outputLen int // output length for full security
|
||||
function code // KIMD/KLMD function code
|
||||
state spongeDirection // whether the sponge is absorbing or squeezing
|
||||
}
|
||||
|
||||
func newAsmState(function code) *asmState {
|
||||
var s asmState
|
||||
s.function = function
|
||||
switch function {
|
||||
case sha3_224:
|
||||
s.rate = 144
|
||||
s.outputLen = 28
|
||||
case sha3_256:
|
||||
s.rate = 136
|
||||
s.outputLen = 32
|
||||
case sha3_384:
|
||||
s.rate = 104
|
||||
s.outputLen = 48
|
||||
case sha3_512:
|
||||
s.rate = 72
|
||||
s.outputLen = 64
|
||||
case shake_128:
|
||||
s.rate = 168
|
||||
s.outputLen = 32
|
||||
case shake_256:
|
||||
s.rate = 136
|
||||
s.outputLen = 64
|
||||
default:
|
||||
panic("sha3: unrecognized function code")
|
||||
}
|
||||
|
||||
// limit s.buf size to a multiple of s.rate
|
||||
s.resetBuf()
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *asmState) clone() *asmState {
|
||||
c := *s
|
||||
c.buf = c.storage[:len(s.buf):cap(s.buf)]
|
||||
return &c
|
||||
}
|
||||
|
||||
// copyIntoBuf copies b into buf. It will panic if there is not enough space to
|
||||
// store all of b.
|
||||
func (s *asmState) copyIntoBuf(b []byte) {
|
||||
bufLen := len(s.buf)
|
||||
s.buf = s.buf[:len(s.buf)+len(b)]
|
||||
copy(s.buf[bufLen:], b)
|
||||
}
|
||||
|
||||
// resetBuf points buf at storage, sets the length to 0 and sets cap to be a
|
||||
// multiple of the rate.
|
||||
func (s *asmState) resetBuf() {
|
||||
max := (cap(s.storage) / s.rate) * s.rate
|
||||
s.buf = s.storage[:0:max]
|
||||
}
|
||||
|
||||
// Write (via the embedded io.Writer interface) adds more data to the running hash.
|
||||
// It never returns an error.
|
||||
func (s *asmState) Write(b []byte) (int, error) {
|
||||
if s.state != spongeAbsorbing {
|
||||
panic("sha3: Write after Read")
|
||||
}
|
||||
length := len(b)
|
||||
for len(b) > 0 {
|
||||
if len(s.buf) == 0 && len(b) >= cap(s.buf) {
|
||||
// Hash the data directly and push any remaining bytes
|
||||
// into the buffer.
|
||||
remainder := len(b) % s.rate
|
||||
kimd(s.function, &s.a, b[:len(b)-remainder])
|
||||
if remainder != 0 {
|
||||
s.copyIntoBuf(b[len(b)-remainder:])
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
if len(s.buf) == cap(s.buf) {
|
||||
// flush the buffer
|
||||
kimd(s.function, &s.a, s.buf)
|
||||
s.buf = s.buf[:0]
|
||||
}
|
||||
|
||||
// copy as much as we can into the buffer
|
||||
n := len(b)
|
||||
if len(b) > cap(s.buf)-len(s.buf) {
|
||||
n = cap(s.buf) - len(s.buf)
|
||||
}
|
||||
s.copyIntoBuf(b[:n])
|
||||
b = b[n:]
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// Read squeezes an arbitrary number of bytes from the sponge.
|
||||
func (s *asmState) Read(out []byte) (n int, err error) {
|
||||
// The 'compute last message digest' instruction only stores the digest
|
||||
// at the first operand (dst) for SHAKE functions.
|
||||
if s.function != shake_128 && s.function != shake_256 {
|
||||
panic("sha3: can only call Read for SHAKE functions")
|
||||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// need to pad if we were absorbing
|
||||
if s.state == spongeAbsorbing {
|
||||
s.state = spongeSqueezing
|
||||
|
||||
// write hash directly into out if possible
|
||||
if len(out)%s.rate == 0 {
|
||||
klmd(s.function, &s.a, out, s.buf) // len(out) may be 0
|
||||
s.buf = s.buf[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// write hash into buffer
|
||||
max := cap(s.buf)
|
||||
if max > len(out) {
|
||||
max = (len(out)/s.rate)*s.rate + s.rate
|
||||
}
|
||||
klmd(s.function, &s.a, s.buf[:max], s.buf)
|
||||
s.buf = s.buf[:max]
|
||||
}
|
||||
|
||||
for len(out) > 0 {
|
||||
// flush the buffer
|
||||
if len(s.buf) != 0 {
|
||||
c := copy(out, s.buf)
|
||||
out = out[c:]
|
||||
s.buf = s.buf[c:]
|
||||
continue
|
||||
}
|
||||
|
||||
// write hash directly into out if possible
|
||||
if len(out)%s.rate == 0 {
|
||||
klmd(s.function|nopad, &s.a, out, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// write hash into buffer
|
||||
s.resetBuf()
|
||||
if cap(s.buf) > len(out) {
|
||||
s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
|
||||
}
|
||||
klmd(s.function|nopad, &s.a, s.buf, nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sum appends the current hash to b and returns the resulting slice.
|
||||
// It does not change the underlying hash state.
|
||||
func (s *asmState) Sum(b []byte) []byte {
|
||||
if s.state != spongeAbsorbing {
|
||||
panic("sha3: Sum after Read")
|
||||
}
|
||||
|
||||
// Copy the state to preserve the original.
|
||||
a := s.a
|
||||
|
||||
// Hash the buffer. Note that we don't clear it because we
|
||||
// aren't updating the state.
|
||||
switch s.function {
|
||||
case sha3_224, sha3_256, sha3_384, sha3_512:
|
||||
klmd(s.function, &a, nil, s.buf)
|
||||
return append(b, a[:s.outputLen]...)
|
||||
case shake_128, shake_256:
|
||||
d := make([]byte, s.outputLen, 64)
|
||||
klmd(s.function, &a, d, s.buf)
|
||||
return append(b, d[:s.outputLen]...)
|
||||
default:
|
||||
panic("sha3: unknown function")
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the Hash to its initial state.
|
||||
func (s *asmState) Reset() {
|
||||
for i := range s.a {
|
||||
s.a[i] = 0
|
||||
}
|
||||
s.resetBuf()
|
||||
s.state = spongeAbsorbing
|
||||
}
|
||||
|
||||
// Size returns the number of bytes Sum will return.
|
||||
func (s *asmState) Size() int {
|
||||
return s.outputLen
|
||||
}
|
||||
|
||||
// BlockSize returns the hash's underlying block size.
|
||||
// The Write method must be able to accept any amount
|
||||
// of data, but it may operate more efficiently if all writes
|
||||
// are a multiple of the block size.
|
||||
func (s *asmState) BlockSize() int {
|
||||
return s.rate
|
||||
}
|
||||
|
||||
// Clone returns a copy of the ShakeHash in its current state.
|
||||
func (s *asmState) Clone() ShakeHash {
|
||||
return s.clone()
|
||||
}
|
||||
|
||||
// new224 returns an assembly implementation of SHA3-224 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new224() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_224)
|
||||
}
|
||||
return new224Generic()
|
||||
}
|
||||
|
||||
// new256 returns an assembly implementation of SHA3-256 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new256() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_256)
|
||||
}
|
||||
return new256Generic()
|
||||
}
|
||||
|
||||
// new384 returns an assembly implementation of SHA3-384 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new384() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_384)
|
||||
}
|
||||
return new384Generic()
|
||||
}
|
||||
|
||||
// new512 returns an assembly implementation of SHA3-512 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func new512() hash.Hash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(sha3_512)
|
||||
}
|
||||
return new512Generic()
|
||||
}
|
||||
|
||||
// newShake128 returns an assembly implementation of SHAKE-128 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func newShake128() ShakeHash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(shake_128)
|
||||
}
|
||||
return newShake128Generic()
|
||||
}
|
||||
|
||||
// newShake256 returns an assembly implementation of SHAKE-256 if available,
|
||||
// otherwise it returns a generic implementation.
|
||||
func newShake256() ShakeHash {
|
||||
if cpu.S390X.HasSHA3 {
|
||||
return newAsmState(shake_256)
|
||||
}
|
||||
return newShake256Generic()
|
||||
}
|
||||
33
vendor/golang.org/x/crypto/sha3/sha3_s390x.s
generated
vendored
33
vendor/golang.org/x/crypto/sha3/sha3_s390x.s
generated
vendored
@@ -1,33 +0,0 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func kimd(function code, chain *[200]byte, src []byte)
|
||||
TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40
|
||||
MOVD function+0(FP), R0
|
||||
MOVD chain+8(FP), R1
|
||||
LMG src+16(FP), R2, R3 // R2=base, R3=len
|
||||
|
||||
continue:
|
||||
WORD $0xB93E0002 // KIMD --, R2
|
||||
BVS continue // continue if interrupted
|
||||
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
|
||||
RET
|
||||
|
||||
// func klmd(function code, chain *[200]byte, dst, src []byte)
|
||||
TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64
|
||||
// TODO: SHAKE support
|
||||
MOVD function+0(FP), R0
|
||||
MOVD chain+8(FP), R1
|
||||
LMG dst+16(FP), R2, R3 // R2=base, R3=len
|
||||
LMG src+40(FP), R4, R5 // R4=base, R5=len
|
||||
|
||||
continue:
|
||||
WORD $0xB93F0024 // KLMD R2, R4
|
||||
BVS continue // continue if interrupted
|
||||
MOVD $0, R0 // reset R0 for pre-go1.8 compilers
|
||||
RET
|
||||
172
vendor/golang.org/x/crypto/sha3/shake.go
generated
vendored
172
vendor/golang.org/x/crypto/sha3/shake.go
generated
vendored
@@ -4,24 +4,10 @@
|
||||
|
||||
package sha3
|
||||
|
||||
// This file defines the ShakeHash interface, and provides
|
||||
// functions for creating SHAKE and cSHAKE instances, as well as utility
|
||||
// functions for hashing bytes to arbitrary-length output.
|
||||
//
|
||||
//
|
||||
// SHAKE implementation is based on FIPS PUB 202 [1]
|
||||
// cSHAKE implementations is based on NIST SP 800-185 [2]
|
||||
//
|
||||
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
||||
// [2] https://doi.org/10.6028/NIST.SP.800-185
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"crypto/sha3"
|
||||
"hash"
|
||||
"io"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// ShakeHash defines the interface to hash functions that support
|
||||
@@ -32,7 +18,7 @@ type ShakeHash interface {
|
||||
hash.Hash
|
||||
|
||||
// Read reads more output from the hash; reading affects the hash's
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum)
|
||||
// state. (ShakeHash.Read is thus very different from Hash.Sum.)
|
||||
// It never returns an error, but subsequent calls to Write or Sum
|
||||
// will panic.
|
||||
io.Reader
|
||||
@@ -41,115 +27,18 @@ type ShakeHash interface {
|
||||
Clone() ShakeHash
|
||||
}
|
||||
|
||||
// cSHAKE specific context
|
||||
type cshakeState struct {
|
||||
*state // SHA-3 state context and Read/Write operations
|
||||
|
||||
// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
|
||||
// by newCShake function and stores concatenation of N followed by S, encoded
|
||||
// by the method specified in 3.3 of [1].
|
||||
// It is stored here in order for Reset() to be able to put context into
|
||||
// initial state.
|
||||
initBlock []byte
|
||||
}
|
||||
|
||||
func bytepad(data []byte, rate int) []byte {
|
||||
out := make([]byte, 0, 9+len(data)+rate-1)
|
||||
out = append(out, leftEncode(uint64(rate))...)
|
||||
out = append(out, data...)
|
||||
if padlen := rate - len(out)%rate; padlen < rate {
|
||||
out = append(out, make([]byte, padlen)...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func leftEncode(x uint64) []byte {
|
||||
// Let n be the smallest positive integer for which 2^(8n) > x.
|
||||
n := (bits.Len64(x) + 7) / 8
|
||||
if n == 0 {
|
||||
n = 1
|
||||
}
|
||||
// Return n || x with n as a byte and x an n bytes in big-endian order.
|
||||
b := make([]byte, 9)
|
||||
binary.BigEndian.PutUint64(b[1:], x)
|
||||
b = b[9-n-1:]
|
||||
b[0] = byte(n)
|
||||
return b
|
||||
}
|
||||
|
||||
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
|
||||
c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
|
||||
c.initBlock = make([]byte, 0, 9+len(N)+9+len(S)) // leftEncode returns max 9 bytes
|
||||
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...)
|
||||
c.initBlock = append(c.initBlock, N...)
|
||||
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...)
|
||||
c.initBlock = append(c.initBlock, S...)
|
||||
c.Write(bytepad(c.initBlock, c.rate))
|
||||
return &c
|
||||
}
|
||||
|
||||
// Reset resets the hash to initial state.
|
||||
func (c *cshakeState) Reset() {
|
||||
c.state.Reset()
|
||||
c.Write(bytepad(c.initBlock, c.rate))
|
||||
}
|
||||
|
||||
// Clone returns copy of a cSHAKE context within its current state.
|
||||
func (c *cshakeState) Clone() ShakeHash {
|
||||
b := make([]byte, len(c.initBlock))
|
||||
copy(b, c.initBlock)
|
||||
return &cshakeState{state: c.clone(), initBlock: b}
|
||||
}
|
||||
|
||||
// Clone returns copy of SHAKE context within its current state.
|
||||
func (c *state) Clone() ShakeHash {
|
||||
return c.clone()
|
||||
}
|
||||
|
||||
func (c *cshakeState) MarshalBinary() ([]byte, error) {
|
||||
return c.AppendBinary(make([]byte, 0, marshaledSize+len(c.initBlock)))
|
||||
}
|
||||
|
||||
func (c *cshakeState) AppendBinary(b []byte) ([]byte, error) {
|
||||
b, err := c.state.AppendBinary(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, c.initBlock...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (c *cshakeState) UnmarshalBinary(b []byte) error {
|
||||
if len(b) <= marshaledSize {
|
||||
return errors.New("sha3: invalid hash state")
|
||||
}
|
||||
if err := c.state.UnmarshalBinary(b[:marshaledSize]); err != nil {
|
||||
return err
|
||||
}
|
||||
c.initBlock = bytes.Clone(b[marshaledSize:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 128 bits against all attacks if at
|
||||
// least 32 bytes of its output are used.
|
||||
func NewShake128() ShakeHash {
|
||||
return newShake128()
|
||||
return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128}
|
||||
}
|
||||
|
||||
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
|
||||
// Its generic security strength is 256 bits against all attacks if
|
||||
// at least 64 bytes of its output are used.
|
||||
func NewShake256() ShakeHash {
|
||||
return newShake256()
|
||||
}
|
||||
|
||||
func newShake128Generic() *state {
|
||||
return &state{rate: rateK256, outputLen: 32, dsbyte: dsbyteShake}
|
||||
}
|
||||
|
||||
func newShake256Generic() *state {
|
||||
return &state{rate: rateK512, outputLen: 64, dsbyte: dsbyteShake}
|
||||
return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256}
|
||||
}
|
||||
|
||||
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
|
||||
@@ -159,10 +48,9 @@ func newShake256Generic() *state {
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake128.
|
||||
func NewCShake128(N, S []byte) ShakeHash {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake128()
|
||||
}
|
||||
return newCShake(N, S, rateK256, 32, dsbyteCShake)
|
||||
return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE {
|
||||
return sha3.NewCSHAKE128(N, S)
|
||||
}}
|
||||
}
|
||||
|
||||
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
|
||||
@@ -172,10 +60,9 @@ func NewCShake128(N, S []byte) ShakeHash {
|
||||
// computations on same input with different S yield unrelated outputs.
|
||||
// When N and S are both empty, this is equivalent to NewShake256.
|
||||
func NewCShake256(N, S []byte) ShakeHash {
|
||||
if len(N) == 0 && len(S) == 0 {
|
||||
return NewShake256()
|
||||
}
|
||||
return newCShake(N, S, rateK512, 64, dsbyteCShake)
|
||||
return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE {
|
||||
return sha3.NewCSHAKE256(N, S)
|
||||
}}
|
||||
}
|
||||
|
||||
// ShakeSum128 writes an arbitrary-length digest of data into hash.
|
||||
@@ -191,3 +78,42 @@ func ShakeSum256(hash, data []byte) {
|
||||
h.Write(data)
|
||||
h.Read(hash)
|
||||
}
|
||||
|
||||
// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE
|
||||
// to implement the ShakeHash interface.
|
||||
type shakeWrapper struct {
|
||||
*sha3.SHAKE
|
||||
outputLen int
|
||||
squeezing bool
|
||||
newSHAKE func() *sha3.SHAKE
|
||||
}
|
||||
|
||||
func (w *shakeWrapper) Read(p []byte) (n int, err error) {
|
||||
w.squeezing = true
|
||||
return w.SHAKE.Read(p)
|
||||
}
|
||||
|
||||
func (w *shakeWrapper) Clone() ShakeHash {
|
||||
s := w.newSHAKE()
|
||||
b, err := w.MarshalBinary()
|
||||
if err != nil {
|
||||
panic(err) // unreachable
|
||||
}
|
||||
if err := s.UnmarshalBinary(b); err != nil {
|
||||
panic(err) // unreachable
|
||||
}
|
||||
return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE}
|
||||
}
|
||||
|
||||
func (w *shakeWrapper) Size() int { return w.outputLen }
|
||||
|
||||
func (w *shakeWrapper) Sum(b []byte) []byte {
|
||||
if w.squeezing {
|
||||
panic("sha3: Sum after Read")
|
||||
}
|
||||
out := make([]byte, w.outputLen)
|
||||
// Clone the state so that we don't affect future Write calls.
|
||||
s := w.Clone()
|
||||
s.Read(out)
|
||||
return append(b, out...)
|
||||
}
|
||||
|
||||
15
vendor/golang.org/x/crypto/sha3/shake_noasm.go
generated
vendored
15
vendor/golang.org/x/crypto/sha3/shake_noasm.go
generated
vendored
@@ -1,15 +0,0 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !gc || purego || !s390x
|
||||
|
||||
package sha3
|
||||
|
||||
func newShake128() *state {
|
||||
return newShake128Generic()
|
||||
}
|
||||
|
||||
func newShake256() *state {
|
||||
return newShake256Generic()
|
||||
}
|
||||
2
vendor/golang.org/x/crypto/ssh/agent/keyring.go
generated
vendored
2
vendor/golang.org/x/crypto/ssh/agent/keyring.go
generated
vendored
@@ -112,7 +112,7 @@ func (r *keyring) Unlock(passphrase []byte) error {
|
||||
}
|
||||
|
||||
// expireKeysLocked removes expired keys from the keyring. If a key was added
|
||||
// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have
|
||||
// with a lifetimesecs constraint and seconds >= lifetimesecs seconds have
|
||||
// elapsed, it is removed. The caller *must* be holding the keyring mutex.
|
||||
func (r *keyring) expireKeysLocked() {
|
||||
for _, k := range r.keys {
|
||||
|
||||
2
vendor/golang.org/x/crypto/ssh/messages.go
generated
vendored
2
vendor/golang.org/x/crypto/ssh/messages.go
generated
vendored
@@ -792,7 +792,7 @@ func marshalString(to []byte, s []byte) []byte {
|
||||
return to[len(s):]
|
||||
}
|
||||
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil))
|
||||
var bigIntType = reflect.TypeFor[*big.Int]()
|
||||
|
||||
// Decode a packet into its corresponding message.
|
||||
func decode(packet []byte) (interface{}, error) {
|
||||
|
||||
25
vendor/modules.txt
vendored
25
vendor/modules.txt
vendored
@@ -754,7 +754,7 @@ github.com/google/go-tpm/tpmutil/tbs
|
||||
# github.com/google/pprof v0.0.0-20250403155104-27863c87afa6
|
||||
## explicit; go 1.23
|
||||
github.com/google/pprof/profile
|
||||
# github.com/google/renameio/v2 v2.0.0
|
||||
# github.com/google/renameio/v2 v2.0.1
|
||||
## explicit; go 1.13
|
||||
github.com/google/renameio/v2
|
||||
# github.com/google/uuid v1.6.0
|
||||
@@ -1355,7 +1355,7 @@ github.com/opencloud-eu/icap-client
|
||||
# github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||
## explicit; go 1.18
|
||||
github.com/opencloud-eu/libre-graph-api-go
|
||||
# github.com/opencloud-eu/reva/v2 v2.39.3-0.20251113164418-9fd6b6864c10
|
||||
# github.com/opencloud-eu/reva/v2 v2.39.3-0.20251120114614-1b573c55f789
|
||||
## explicit; go 1.24.1
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/runtime
|
||||
@@ -1772,8 +1772,8 @@ github.com/orcaman/concurrent-map
|
||||
# github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
||||
## explicit; go 1.12
|
||||
github.com/oxtoacart/bpool
|
||||
# github.com/pablodz/inotifywaitgo v0.0.9
|
||||
## explicit; go 1.23.1
|
||||
# github.com/pablodz/inotifywaitgo v0.0.9 => github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9
|
||||
## explicit; go 1.24.1
|
||||
github.com/pablodz/inotifywaitgo/inotifywaitgo
|
||||
# github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
## explicit
|
||||
@@ -1891,6 +1891,18 @@ github.com/russross/blackfriday/v2
|
||||
## explicit
|
||||
github.com/rwcarlsen/goexif/exif
|
||||
github.com/rwcarlsen/goexif/tiff
|
||||
# github.com/samber/lo v1.51.0
|
||||
## explicit; go 1.18
|
||||
github.com/samber/lo
|
||||
github.com/samber/lo/internal/constraints
|
||||
github.com/samber/lo/internal/rand
|
||||
github.com/samber/lo/mutable
|
||||
# github.com/samber/slog-common v0.19.0
|
||||
## explicit; go 1.21
|
||||
github.com/samber/slog-common
|
||||
# github.com/samber/slog-zerolog/v2 v2.9.0
|
||||
## explicit; go 1.21
|
||||
github.com/samber/slog-zerolog/v2
|
||||
# github.com/segmentio/asm v1.2.0
|
||||
## explicit; go 1.18
|
||||
github.com/segmentio/asm/base64
|
||||
@@ -2292,7 +2304,6 @@ go.opentelemetry.io/otel/internal/global
|
||||
go.opentelemetry.io/otel/propagation
|
||||
go.opentelemetry.io/otel/semconv/internal
|
||||
go.opentelemetry.io/otel/semconv/internal/v4
|
||||
go.opentelemetry.io/otel/semconv/v1.10.0
|
||||
go.opentelemetry.io/otel/semconv/v1.20.0
|
||||
go.opentelemetry.io/otel/semconv/v1.20.0/httpconv
|
||||
go.opentelemetry.io/otel/semconv/v1.21.0
|
||||
@@ -2366,7 +2377,7 @@ go.yaml.in/yaml/v2
|
||||
# go.yaml.in/yaml/v3 v3.0.4
|
||||
## explicit; go 1.16
|
||||
go.yaml.in/yaml/v3
|
||||
# golang.org/x/crypto v0.43.0
|
||||
# golang.org/x/crypto v0.44.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/crypto/argon2
|
||||
golang.org/x/crypto/bcrypt
|
||||
@@ -2466,7 +2477,7 @@ golang.org/x/sys/windows/svc/mgr
|
||||
# golang.org/x/term v0.37.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/term
|
||||
# golang.org/x/text v0.30.0
|
||||
# golang.org/x/text v0.31.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/text/cases
|
||||
golang.org/x/text/encoding
|
||||
|
||||
Reference in New Issue
Block a user