Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

19
vendor/go.uber.org/dig/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,19 @@
coverage:
range: 70..98
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 97 # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure
patch:
default:
enabled: yes
target: 70

12
vendor/go.uber.org/dig/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,12 @@
/bin
/vendor
/.bench
*.mem
*.cpu
*.test
*.log
*.out
*.html
*.coverprofile
coverage.txt
*.pprof

309
vendor/go.uber.org/dig/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,309 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [1.17.1] - 2023-10-19
### Added
- Suggestions for value vs. pointer elements for slice and array types.
### Fixed
- An issue where value group values were not getting decorated
by decorators within the same module when using dig.Export(true).
- A typo in docs.
- An issue where false positives in cycle detection were occurring
when providing to a child scope.
Thanks to @paullen and @lcarilla for their contributions to this release.
[1.17.1]: https://github.com/uber-go/dig/compare/v1.17.0...v1.17.1
## [1.17.0] - 2023-05-02
### Added
- Allow using `dig.As` with `dig.Group`.
- Add `FillInvokeInfo` Option and `InvokeInfo` struct to help
extract the types requested by an `Invoke` statement.
- To get visibility into constructor and decorator calls, introduce
`WithProviderCallback` and `WithDecoratorCallback` Options to provide callback functions.
[1.17.0]: https://github.com/uber-go/dig/compare/v1.16.1...v1.17.0
## [1.16.1] - 2023-01-10
### Fixed
- A panic when `DryRun` was used with `Decorate`.
[1.16.1]: https://github.com/uber-go/dig/compare/v1.16.0...v1.16.1
## [1.16.0] - 2023-01-03
### Added
- Add `RecoverFromPanics` option, which provides panic-recovery mechanism for Container.
- Add `Error` interface which enables distinguishing errors from Dig using standard `errors`
package.
Thanks to @mie998 for their contribution(s) to this release.
[1.16.0]: https://github.com/uber-go/dig/compare/v1.15.0...v1.16.0
## [1.15.0] - 2022-08-02
### Added
- Support for `soft` value groups, which specify a value group that only gets populated
with values from already-executed constructors.
### Fixed
- Fix an issue with invoke order affecting results provided by private provides
Thanks to @hbdf for their contributions to this release.
[1.15.0]: https://github.com/uber-go/dig/compare/v1.14.1...v1.15.0
## [1.14.1] - 2022-03-22
### Fixed
- Fix an issue where a dependency for a decoration supplied by another decorator in the
same scope is ignored.
- Fix a panic when submitting a single value as a value group in `Scope.Decorate`.
- Upon a provide error, make the error message contain the function named specified
by LocationForPC Option.
[1.14.1]: https://github.com/uber-go/dig/compare/v1.14.0...v1.14.1
## [1.14.0] - 2022-02-23
### Added
- Introduce `dig.Scope` which creates a scoped dependency injection
container to scope dependencies.
- Introduce `Scope.Decorate` and `Container.Decorate` which allows a
decorator to modify a dependency already provided in the dependency graph.
- Add `FillDecorateInfo` Option and `DecorateInfo` struct which exposes
information on what Dig was able to understand from the decorator provided
with `Scope.Decorate` or `Container.Decorate`.
### Changed
- The error message that appears when a cycle is detected in the dependency graph
has been changed slightly.
### Fixed
- A stack overflow bug that happens when cycles are introduced via self-pointing
dependencies with DeferAcyclicVerification.
[1.14.0]: https://github.com/uber-go/dig/compare/v1.13.0...v1.14.0
## [1.13.0] - 2021-09-21
### Added
- Introduce `As` option which supports providing a type as interface(s)
it implements to the container.
- Add `LocationForPC` option which overrides the function inspection
for a program counter address to a provided function info.
[1.13.0]: https://github.com/uber-go/dig/compare/v1.12.0...v1.13.0
## [1.12.0] - 2021-07-29
### Added
- Support for ProvideInfo and FillProvideInfo that allow the caller of
`Provide` to get info about what dig understood from the constructor.
[1.12.0]: https://github.com/uber-go/dig/compare/v1.11.0...v1.12.0
## [1.11.0] - 2021-06-09
### Added
- Support unexported fields on `dig.In` structs with the
`ignore-unexported:"true` struct tag.
[1.11.0]: https://github.com/uber-go/dig/compare/v1.10.0...v1.11.0
## [1.10.0] - 2020-06-16
### Added
- Introduce `DryRun` Option which, when set to true, disables invocation
of functions supplied to `Provide` and `Invoke`. This option will be
used to build no-op containers, for example for `fx.ValidateApp` method.
[1.10.0]: https://github.com/uber-go/dig/compare/v1.9.0...v1.10.0
## [1.9.0] - 2020-03-31
### Added
- GraphViz visualization of the graph now includes names of packages next to
constructors.
- Added a `flatten` modifier to group tags for slices to allow providing
individual elements instead of the slice for a group value. See package
doucmentation for more information.
### Changed
- Drop library dependency on `golang.org/x/lint`.
- Support printing multi-line error messages with `%+v`.
[1.9.0]: https://github.com/uber-go/dig/compare/v1.8.0...v1.9.0
## [1.8.0] - 2019-11-14
### Changed
- Migrated to Go modules.
[1.8.0]: https://github.com/uber-go/dig/compare/v1.7.0...v1.8.0
## [1.7.0] - 2019-01-04
### Added
- Added `Group` option for `Provide` to add value groups to the container without
rewriting constructors. See package doucmentation for more information.
[1.7.0]: https://github.com/uber-go/dig/compare/v1.6.0...v1.7.0
## [1.6.0] - 2018-11-06
### Changed
- When an error graph is visualized, the graph is pruned so that the graph only
contains failure nodes.
- Container visualization is now oriented from right to left.
[1.6.0]: https://github.com/uber-go/dig/compare/v1.5.1...v1.6.0
## [1.5.1] - 2018-11-01
### Fixed
- Fixed a test that was causing Dig to be unusable with Go Modules.
[1.5.1]: https://github.com/uber-go/dig/compare/v1.5.0...v1.5.1
## [1.5.0] - 2018-09-19
### Added
- Added a `DeferAcyclicVerification` container option that defers graph cycle
detection until the next Invoke.
### Changed
- Improved cycle-detection performance by 50x in certain degenerative cases.
[1.5.0]: https://github.com/uber-go/dig/compare/v1.4.0...v1.5.0
## [1.4.0] - 2018-08-16
### Added
- Added `Visualize` function to visualize the state of the container in the
GraphViz DOT format. This allows visualization of error types and the
dependency relationships of types in the container.
- Added `CanVisualizeError` function to determine if an error can be visualized
in the graph.
- Added `Name` option for `Provide` to add named values to the container
without rewriting constructors. See package documentation for more
information.
### Changed
- `name:"..."` tags on nested Result Objects will now cause errors instead of
being ignored.
[1.4.0]: https://github.com/uber-go/dig/compare/v1.3.0...v1.4.0
## [1.3.0] - 2017-12-04
### Changed
- Improved messages for errors thrown by Dig under a many scenarios to be more
informative.
[1.3.0]: https://github.com/uber-go/dig/compare/v1.2.0...v1.3.0
## [1.2.0] - 2017-11-07
### Added
- `dig.In` and `dig.Out` now support value groups, making it possible to
produce many values of the same type from different constructors. See package
documentation for more information.
[1.2.0]: https://github.com/uber-go/dig/compare/v1.1.0...v1.2.0
## [1.1.0] - 2017-09-15
### Added
- Added the `dig.RootCause` function which allows retrieving the original
constructor error that caused an `Invoke` failure.
### Changed
- Errors from `Invoke` now attempt to hint to the user a presence of a similar
type, for example a pointer to the requested type and vice versa.
[1.1.0]: https://github.com/uber-go/dig/compare/v1.0.0...v1.1.0
## [1.0.0] - 2017-07-31
First stable release: no breaking changes will be made in the 1.x series.
### Changed
- `Provide` and `Invoke` will now fail if `dig.In` or `dig.Out` structs
contain unexported fields. Previously these fields were ignored which often
led to confusion.
[1.0.0]: https://github.com/uber-go/dig/compare/v1.0.0-rc2...v1.0.0
## [1.0.0-rc2] - 2017-07-21
### Added
- Exported `dig.IsIn` and `dig.IsOut` so that consuming libraries can check if
a params or return struct embeds the `dig.In` and `dig.Out` types, respectively.
### Changed
- Added variadic options to all public APIS so that new functionality can be
introduced post v1.0.0 without introducing breaking changes.
- Functions with variadic arguments can now be passed to `dig.Provide` and
`dig.Invoke`. Previously this caused an error, whereas now the args will be ignored.
[1.0.0-rc2]: https://github.com/uber-go/dig/compare/v1.0.0-rc1...v1.0.0-rc2
## [1.0.0-rc1] - 2017-06-21
First release candidate.
[1.0.0-rc1]: https://github.com/uber-go/dig/compare/v0.5.0...v1.0.0-rc1
## [0.5.0] - 2017-06-19
### Added
- `dig.In` and `dig.Out` now support named instances, i.e.:
```go
type param struct {
dig.In
DB1 DB.Connection `name:"primary"`
DB2 DB.Connection `name:"secondary"`
}
```
### Fixed
- Structs compatible with `dig.In` and `dig.Out` may now be generated using
`reflect.StructOf`.
[0.5.0]: https://github.com/uber-go/dig/compare/v0.4.0...v0.5.0
## [0.4.0] - 2017-06-12
### Added
- Add `dig.In` embeddable type for advanced use-cases of specifying dependencies.
- Add `dig.Out` embeddable type for advanced use-cases of constructors
inserting types in the container.
- Add support for optional parameters through `optional:"true"` tag on `dig.In` objects.
- Add support for value types and many built-ins (maps, slices, channels).
### Changed
- **[Breaking]** Restrict the API surface to only `Provide` and `Invoke`.
- **[Breaking]** Update `Provide` method to accept variadic arguments.
### Removed
- **[Breaking]** Remove `Must*` funcs to greatly reduce API surface area.
- Providing constructors with common returned types results in an error.
[0.4.0]: https://github.com/uber-go/dig/compare/v0.3...v0.4.0
## [0.3] - 2017-05-02
### Added
- Add functionality to `Provide` to support constructor with `n` return
objects to be resolved into the `dig.Graph`
- Add `Invoke` function to invoke provided function and insert return
objects into the `dig.Graph`
### Changed
- Rename `RegisterAll` and `MustRegisterAll` to `ProvideAll` and
`MustProvideAll`.
[0.3]: https://github.com/uber-go/dig/compare/v0.2...v0.3
## [0.2] - 2017-03-27
### Changed
- Rename `Register` to `Provide` for clarity and to recude clash with other
Register functions.
- Rename `dig.Graph` to `dig.Container`.
### Removed
- Remove the package-level functions and the `DefaultGraph`.
[0.2]: https://github.com/uber-go/dig/compare/v0.1...v0.2
## 0.1 - 2017-03-23
Initial release.

19
vendor/go.uber.org/dig/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2017-2018 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

67
vendor/go.uber.org/dig/Makefile generated vendored Normal file
View File

@@ -0,0 +1,67 @@
export GOBIN ?= $(shell pwd)/bin
GOLINT = $(GOBIN)/golint
STATICCHECK = $(GOBIN)/staticcheck
BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem
GO_FILES = $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
MODULES = . ./tools
.PHONY: all
all: build lint test
.PHONY: build
build:
go build ./...
.PHONY: install
install:
$(foreach dir,$(MODULES),( \
cd $(dir) && \
go mod download) && \
) true
.PHONY: lint
lint: $(GOLINT) $(STATICCHECK)
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log
@echo "Checking vet..."
@go vet ./... 2>&1 | tee -a lint.log
@echo "Checking lint..."
@$(GOLINT) ./... 2>&1 | tee -a lint.log
@echo "Checking staticcheck..."
@$(STATICCHECK) ./... 2>&1 | tee -a lint.log
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e Makefile | tee -a lint.log
@echo "Checking for license headers..."
@./check_license.sh | tee -a lint.log
@[ ! -s lint.log ]
$(GOLINT): tools/go.mod
cd tools && go install golang.org/x/lint/golint
$(STATICCHECK): tools/go.mod
cd tools && go install honnef.co/go/tools/cmd/staticcheck
.PHONY: test
test:
go test -race ./...
.PHONY: cover
cover:
go test -race -coverprofile=cover.out -coverpkg=./... ./...
go tool cover -html=cover.out -o cover.html
.PHONY: bench
BENCH ?= .
bench:
go list ./... | xargs -n1 go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS)
.PHONY: tidy
tidy:
$(foreach dir,$(MODULES),(cd $(dir) && go mod tidy) &&) true

51
vendor/go.uber.org/dig/README.md generated vendored Normal file
View File

@@ -0,0 +1,51 @@
# :hammer_and_pick: dig [![GoDoc][doc-img]][doc] [![GitHub release][release-img]][release] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][report-card-img]][report-card]
A reflection based dependency injection toolkit for Go.
### Good for:
* Powering an application framework, e.g. [Fx](https://github.com/uber-go/fx).
* Resolving the object graph during process startup.
### Bad for:
* Using in place of an application framework, e.g. [Fx](https://github.com/uber-go/fx).
* Resolving dependencies after the process has already started.
* Exposing to user-land code as a [Service Locator](https://martinfowler.com/articles/injection.html#UsingAServiceLocator).
## Installation
We recommend consuming [SemVer](http://semver.org/) major version `1` using
your dependency manager of choice.
```
$ glide get 'go.uber.org/dig#^1'
$ dep ensure -add "go.uber.org/dig@v1"
$ go get 'go.uber.org/dig@v1'
```
## Stability
This library is `v1` and follows [SemVer](http://semver.org/) strictly.
No breaking changes will be made to exported APIs before `v2.0.0`.
[doc-img]: http://img.shields.io/badge/GoDoc-Reference-blue.svg
[doc]: https://godoc.org/go.uber.org/dig
[release-img]: https://img.shields.io/github/release/uber-go/dig.svg
[release]: https://github.com/uber-go/dig/releases
[ci-img]: https://github.com/uber-go/dig/actions/workflows/go.yml/badge.svg
[ci]: https://github.com/uber-go/dig/actions/workflows/go.yml
[cov-img]: https://codecov.io/gh/uber-go/dig/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/dig/branch/master
[report-card-img]: https://goreportcard.com/badge/github.com/uber-go/dig
[report-card]: https://goreportcard.com/report/github.com/uber-go/dig
## Stargazers over time
[![Stargazers over time](https://starchart.cc/uber-go/dig.svg)](https://starchart.cc/uber-go/dig)

108
vendor/go.uber.org/dig/callback.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
// CallbackInfo contains information about a provided function or decorator
// called by Dig, and is passed to a [Callback] registered with
// [WithProviderCallback] or [WithDecoratorCallback].
type CallbackInfo struct {
// Name is the name of the function in the format:
// <package_name>.<function_name>
Name string
// Error contains the error returned by the [Callback]'s associated
// function, if any. When used in conjunction with [RecoverFromPanics],
// this will be set to a [PanicError] when the function panics.
Error error
}
// Callback is a function that can be registered with a provided function
// or decorator with [WithCallback] to cause it to be called after the
// provided function or decorator is run.
type Callback func(CallbackInfo)
// WithProviderCallback returns a [ProvideOption] which has Dig call
// the passed in [Callback] after the corresponding constructor finishes running.
//
// For example, the following prints a completion message
// after "myConstructor" finishes, including the error if any:
//
// c := dig.New()
// myCallback := func(ci CallbackInfo) {
// var errorAdd string
// if ci.Error != nil {
// errorAdd = fmt.Sprintf("with error: %v", ci.Error)
// }
// fmt.Printf("%q finished%v", ci.Name, errorAdd)
// }
// c.Provide(myConstructor, WithProviderCallback(myCallback)),
//
// Callbacks can also be specified for Decorators with [WithDecoratorCallback].
//
// See [CallbackInfo] for more info on the information passed to the [Callback].
func WithProviderCallback(callback Callback) ProvideOption {
return withCallbackOption{
callback: callback,
}
}
// WithDecoratorCallback returns a [DecorateOption] which has Dig call
// the passed in [Callback] after the corresponding decorator finishes running.
//
// For example, the following prints a completion message
// after "myDecorator" finishes, including the error if any:
//
// c := dig.New()
// myCallback := func(ci CallbackInfo) {
// var errorAdd string
// if ci.Error != nil {
// errorAdd = fmt.Sprintf("with error: %v", ci.Error)
// }
// fmt.Printf("%q finished%v", ci.Name, errorAdd)
// }
// c.Decorate(myDecorator, WithDecoratorCallback(myCallback)),
//
// Callbacks can also be specified for Constructors with [WithProviderCallback].
//
// See [CallbackInfo] for more info on the information passed to the [Callback].
func WithDecoratorCallback(callback Callback) DecorateOption {
return withCallbackOption{
callback: callback,
}
}
type withCallbackOption struct {
callback Callback
}
var (
_ ProvideOption = withCallbackOption{}
_ DecorateOption = withCallbackOption{}
)
func (o withCallbackOption) applyProvideOption(po *provideOptions) {
po.Callback = o.callback
}
func (o withCallbackOption) apply(do *decorateOptions) {
do.Callback = o.callback
}

17
vendor/go.uber.org/dig/check_license.sh generated vendored Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/bash -e
ERROR_COUNT=0
while read -r file
do
case "$(head -1 "${file}")" in
*"Copyright (c) "*" Uber Technologies, Inc.")
# everything's cool
;;
*)
echo "$file is missing license header."
(( ERROR_COUNT++ ))
;;
esac
done < <(git ls-files "*\.go")
exit $ERROR_COUNT

243
vendor/go.uber.org/dig/constructor.go generated vendored Normal file
View File

@@ -0,0 +1,243 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"reflect"
"go.uber.org/dig/internal/digerror"
"go.uber.org/dig/internal/digreflect"
"go.uber.org/dig/internal/dot"
)
// constructorNode is a node in the dependency graph that represents
// a constructor provided by the user.
//
// constructorNodes can produce zero or more values that they store into the container.
// For the Provide path, we verify that constructorNodes produce at least one value,
// otherwise the function will never be called.
type constructorNode struct {
ctor interface{}
ctype reflect.Type
// Location where this function was defined.
location *digreflect.Func
// id uniquely identifies the constructor that produces a node.
id dot.CtorID
// Whether the constructor owned by this node was already called.
called bool
// Type information about constructor parameters.
paramList paramList
// Type information about constructor results.
resultList resultList
// Order of this node in each Scopes' graphHolders.
orders map[*Scope]int
// Scope this node is part of.
s *Scope
// Scope this node was originally provided to.
// This is different from s if and only if the constructor was Provided with ExportOption.
origS *Scope
// Callback for this provided function, if there is one.
callback Callback
}
type constructorOptions struct {
// If specified, all values produced by this constructor have the provided name
// belong to the specified value group or implement any of the interfaces.
ResultName string
ResultGroup string
ResultAs []interface{}
Location *digreflect.Func
Callback Callback
}
func newConstructorNode(ctor interface{}, s *Scope, origS *Scope, opts constructorOptions) (*constructorNode, error) {
cval := reflect.ValueOf(ctor)
ctype := cval.Type()
cptr := cval.Pointer()
params, err := newParamList(ctype, s)
if err != nil {
return nil, err
}
results, err := newResultList(
ctype,
resultOptions{
Name: opts.ResultName,
Group: opts.ResultGroup,
As: opts.ResultAs,
},
)
if err != nil {
return nil, err
}
location := opts.Location
if location == nil {
location = digreflect.InspectFunc(ctor)
}
n := &constructorNode{
ctor: ctor,
ctype: ctype,
location: location,
id: dot.CtorID(cptr),
paramList: params,
resultList: results,
orders: make(map[*Scope]int),
s: s,
origS: origS,
callback: opts.Callback,
}
s.newGraphNode(n, n.orders)
return n, nil
}
func (n *constructorNode) Location() *digreflect.Func { return n.location }
func (n *constructorNode) ParamList() paramList { return n.paramList }
func (n *constructorNode) ResultList() resultList { return n.resultList }
func (n *constructorNode) ID() dot.CtorID { return n.id }
func (n *constructorNode) CType() reflect.Type { return n.ctype }
func (n *constructorNode) Order(s *Scope) int { return n.orders[s] }
func (n *constructorNode) OrigScope() *Scope { return n.origS }
// CopyOrder copies the order for the given parent scope to the given child scope.
func (n *constructorNode) CopyOrder(parent, child *Scope) {
n.orders[child] = n.orders[parent]
}
func (n *constructorNode) String() string {
return fmt.Sprintf("deps: %v, ctor: %v", n.paramList, n.ctype)
}
// Call calls this constructor if it hasn't already been called and
// injects any values produced by it into the provided container.
func (n *constructorNode) Call(c containerStore) (err error) {
if n.called {
return nil
}
if err := shallowCheckDependencies(c, n.paramList); err != nil {
return errMissingDependencies{
Func: n.location,
Reason: err,
}
}
args, err := n.paramList.BuildList(c)
if err != nil {
return errArgumentsFailed{
Func: n.location,
Reason: err,
}
}
if n.callback != nil {
// Wrap in separate func to include PanicErrors
defer func() {
n.callback(CallbackInfo{
Name: fmt.Sprintf("%v.%v", n.location.Package, n.location.Name),
Error: err,
})
}()
}
if n.s.recoverFromPanics {
defer func() {
if p := recover(); p != nil {
err = PanicError{
fn: n.location,
Panic: p,
}
}
}()
}
receiver := newStagingContainerWriter()
results := c.invoker()(reflect.ValueOf(n.ctor), args)
if err = n.resultList.ExtractList(receiver, false /* decorating */, results); err != nil {
return errConstructorFailed{Func: n.location, Reason: err}
}
// Commit the result to the original container that this constructor
// was supplied to. The provided constructor is only used for a view of
// the rest of the graph to instantiate the dependencies of this
// container.
receiver.Commit(n.s)
n.called = true
return nil
}
// stagingContainerWriter is a containerWriter that records the changes that
// would be made to a containerWriter and defers them until Commit is called.
type stagingContainerWriter struct {
values map[key]reflect.Value
groups map[key][]reflect.Value
}
var _ containerWriter = (*stagingContainerWriter)(nil)
func newStagingContainerWriter() *stagingContainerWriter {
return &stagingContainerWriter{
values: make(map[key]reflect.Value),
groups: make(map[key][]reflect.Value),
}
}
func (sr *stagingContainerWriter) setValue(name string, t reflect.Type, v reflect.Value) {
sr.values[key{t: t, name: name}] = v
}
func (sr *stagingContainerWriter) setDecoratedValue(_ string, _ reflect.Type, _ reflect.Value) {
digerror.BugPanicf("stagingContainerWriter.setDecoratedValue must never be called")
}
func (sr *stagingContainerWriter) submitGroupedValue(group string, t reflect.Type, v reflect.Value) {
k := key{t: t, group: group}
sr.groups[k] = append(sr.groups[k], v)
}
func (sr *stagingContainerWriter) submitDecoratedGroupedValue(_ string, _ reflect.Type, _ reflect.Value) {
digerror.BugPanicf("stagingContainerWriter.submitDecoratedGroupedValue must never be called")
}
// Commit commits the received results to the provided containerWriter.
func (sr *stagingContainerWriter) Commit(cw containerWriter) {
for k, v := range sr.values {
cw.setValue(k.name, k.t, v)
}
for k, vs := range sr.groups {
for _, v := range vs {
cw.submitGroupedValue(k.group, k.t, v)
}
}
}

282
vendor/go.uber.org/dig/container.go generated vendored Normal file
View File

@@ -0,0 +1,282 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"math/rand"
"reflect"
"go.uber.org/dig/internal/dot"
)
const (
_optionalTag = "optional"
_nameTag = "name"
_ignoreUnexportedTag = "ignore-unexported"
)
// Unique identification of an object in the graph.
type key struct {
t reflect.Type
// Only one of name or group will be set.
name string
group string
}
func (k key) String() string {
if k.name != "" {
return fmt.Sprintf("%v[name=%q]", k.t, k.name)
}
if k.group != "" {
return fmt.Sprintf("%v[group=%q]", k.t, k.group)
}
return k.t.String()
}
// Option configures a Container.
type Option interface {
applyOption(*Container)
}
// Container is a directed acyclic graph of types and their dependencies.
// A Container is the root Scope that represents the top-level scoped
// directed acyclic graph of the dependencies.
type Container struct {
// this is the "root" Scope that represents the
// root of the scope tree.
scope *Scope
}
// containerWriter provides write access to the Container's underlying data
// store.
type containerWriter interface {
// setValue sets the value with the given name and type in the container.
// If a value with the same name and type already exists, it will be
// overwritten.
setValue(name string, t reflect.Type, v reflect.Value)
// setDecoratedValue sets a decorated value with the given name and type
// in the container. If a decorated value with the same name and type already
// exists, it will be overwritten.
setDecoratedValue(name string, t reflect.Type, v reflect.Value)
// submitGroupedValue submits a value to the value group with the provided
// name.
submitGroupedValue(name string, t reflect.Type, v reflect.Value)
// submitDecoratedGroupedValue submits a decorated value to the value group
// with the provided name.
submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value)
}
// containerStore provides access to the Container's underlying data store.
type containerStore interface {
containerWriter
// Adds a new graph node to the Container
newGraphNode(w interface{}, orders map[*Scope]int)
// Returns a slice containing all known types.
knownTypes() []reflect.Type
// Retrieves the value with the provided name and type, if any.
getValue(name string, t reflect.Type) (v reflect.Value, ok bool)
// Retrieves a decorated value with the provided name and type, if any.
getDecoratedValue(name string, t reflect.Type) (v reflect.Value, ok bool)
// Retrieves all values for the provided group and type.
//
// The order in which the values are returned is undefined.
getValueGroup(name string, t reflect.Type) []reflect.Value
// Retrieves all decorated values for the provided group and type, if any.
getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool)
// Returns the providers that can produce a value with the given name and
// type.
getValueProviders(name string, t reflect.Type) []provider
// Returns the providers that can produce values for the given group and
// type.
getGroupProviders(name string, t reflect.Type) []provider
// Returns the providers that can produce a value with the given name and
// type across all the Scopes that are in effect of this containerStore.
getAllValueProviders(name string, t reflect.Type) []provider
// Returns the decorator that can decorate values for the given name and
// type.
getValueDecorator(name string, t reflect.Type) (decorator, bool)
// Reutrns the decorator that can decorate values for the given group and
// type.
getGroupDecorator(name string, t reflect.Type) (decorator, bool)
// Reports a list of stores (starting at this store) up to the root
// store.
storesToRoot() []containerStore
createGraph() *dot.Graph
// Returns invokerFn function to use when calling arguments.
invoker() invokerFn
}
// New constructs a Container.
func New(opts ...Option) *Container {
s := newScope()
c := &Container{scope: s}
for _, opt := range opts {
opt.applyOption(c)
}
return c
}
// DeferAcyclicVerification is an Option to override the default behavior
// of container.Provide, deferring the dependency graph validation to no longer
// run after each call to container.Provide. The container will instead verify
// the graph on first `Invoke`.
//
// Applications adding providers to a container in a tight loop may experience
// performance improvements by initializing the container with this option.
func DeferAcyclicVerification() Option {
return deferAcyclicVerificationOption{}
}
type deferAcyclicVerificationOption struct{}
func (deferAcyclicVerificationOption) String() string {
return "DeferAcyclicVerification()"
}
func (deferAcyclicVerificationOption) applyOption(c *Container) {
c.scope.deferAcyclicVerification = true
}
// RecoverFromPanics is an [Option] to recover from panics that occur while
// running functions given to the container. When set, recovered panics
// will be placed into a [PanicError], and returned at the invoke callsite.
// See [PanicError] for an example on how to handle panics with this option
// enabled, and distinguish them from errors.
func RecoverFromPanics() Option {
return recoverFromPanicsOption{}
}
type recoverFromPanicsOption struct{}
func (recoverFromPanicsOption) String() string {
return "RecoverFromPanics()"
}
func (recoverFromPanicsOption) applyOption(c *Container) {
c.scope.recoverFromPanics = true
}
// Changes the source of randomness for the container.
//
// This will help provide determinism during tests.
func setRand(r *rand.Rand) Option {
return setRandOption{r: r}
}
type setRandOption struct{ r *rand.Rand }
func (o setRandOption) String() string {
return fmt.Sprintf("setRand(%p)", o.r)
}
func (o setRandOption) applyOption(c *Container) {
c.scope.rand = o.r
}
// DryRun is an Option which, when set to true, disables invocation of functions supplied to
// Provide and Invoke. Use this to build no-op containers.
func DryRun(dry bool) Option {
return dryRunOption(dry)
}
type dryRunOption bool
func (o dryRunOption) String() string {
return fmt.Sprintf("DryRun(%v)", bool(o))
}
func (o dryRunOption) applyOption(c *Container) {
if o {
c.scope.invokerFn = dryInvoker
} else {
c.scope.invokerFn = defaultInvoker
}
}
// invokerFn specifies how the container calls user-supplied functions.
type invokerFn func(fn reflect.Value, args []reflect.Value) (results []reflect.Value)
func defaultInvoker(fn reflect.Value, args []reflect.Value) []reflect.Value {
return fn.Call(args)
}
// Generates zero values for results without calling the supplied function.
func dryInvoker(fn reflect.Value, _ []reflect.Value) []reflect.Value {
ft := fn.Type()
results := make([]reflect.Value, ft.NumOut())
for i := 0; i < ft.NumOut(); i++ {
results[i] = reflect.Zero(fn.Type().Out(i))
}
return results
}
// String representation of the entire Container
func (c *Container) String() string {
return c.scope.String()
}
// Scope creates a child scope of the Container with the given name.
func (c *Container) Scope(name string, opts ...ScopeOption) *Scope {
return c.scope.Scope(name, opts...)
}
type byTypeName []reflect.Type
func (bs byTypeName) Len() int {
return len(bs)
}
func (bs byTypeName) Less(i int, j int) bool {
return fmt.Sprint(bs[i]) < fmt.Sprint(bs[j])
}
func (bs byTypeName) Swap(i int, j int) {
bs[i], bs[j] = bs[j], bs[i]
}
func shuffledCopy(rand *rand.Rand, items []reflect.Value) []reflect.Value {
newItems := make([]reflect.Value, len(items))
for i, j := range rand.Perm(len(items)) {
newItems[i] = items[j]
}
return newItems
}

79
vendor/go.uber.org/dig/cycle_error.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"bytes"
"errors"
"fmt"
"io"
"go.uber.org/dig/internal/digreflect"
)
type cycleErrPathEntry struct {
Key key
Func *digreflect.Func
}
type errCycleDetected struct {
Path []cycleErrPathEntry
scope *Scope
}
var _ digError = errCycleDetected{}
func (e errCycleDetected) Error() string {
// We get something like,
//
// [scope "foo"]
// func(*bar) *foo provided by "path/to/package".NewFoo (path/to/file.go:42)
// depends on func(*baz) *bar provided by "another/package".NewBar (somefile.go:1)
// depends on func(*foo) baz provided by "somepackage".NewBar (anotherfile.go:2)
// depends on func(*bar) *foo provided by "path/to/package".NewFoo (path/to/file.go:42)
//
b := new(bytes.Buffer)
if name := e.scope.name; len(name) > 0 {
fmt.Fprintf(b, "[scope %q]\n", name)
}
for i, entry := range e.Path {
if i > 0 {
b.WriteString("\n\tdepends on ")
}
fmt.Fprintf(b, "%v provided by %v", entry.Key, entry.Func)
}
return b.String()
}
func (e errCycleDetected) writeMessage(w io.Writer, v string) {
fmt.Fprint(w, e.Error())
}
func (e errCycleDetected) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
// IsCycleDetected returns a boolean as to whether the provided error indicates
// a cycle was detected in the container graph.
func IsCycleDetected(err error) bool {
return errors.As(err, &errCycleDetected{})
}

313
vendor/go.uber.org/dig/decorate.go generated vendored Normal file
View File

@@ -0,0 +1,313 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"reflect"
"go.uber.org/dig/internal/digreflect"
"go.uber.org/dig/internal/dot"
)
type decoratorState int
const (
decoratorReady decoratorState = iota
decoratorOnStack
decoratorCalled
)
type decorator interface {
Call(c containerStore) error
ID() dot.CtorID
State() decoratorState
}
type decoratorNode struct {
dcor interface{}
dtype reflect.Type
id dot.CtorID
// Location where this function was defined.
location *digreflect.Func
// Current state of this decorator
state decoratorState
// Parameters of the decorator.
params paramList
// Results of the decorator.
results resultList
// Order of this node in each Scopes' graphHolders.
orders map[*Scope]int
// Scope this node was originally provided to.
s *Scope
// Callback for this decorator, if there is one.
callback Callback
}
func newDecoratorNode(dcor interface{}, s *Scope, opts decorateOptions) (*decoratorNode, error) {
dval := reflect.ValueOf(dcor)
dtype := dval.Type()
dptr := dval.Pointer()
pl, err := newParamList(dtype, s)
if err != nil {
return nil, err
}
rl, err := newResultList(dtype, resultOptions{})
if err != nil {
return nil, err
}
n := &decoratorNode{
dcor: dcor,
dtype: dtype,
id: dot.CtorID(dptr),
location: digreflect.InspectFunc(dcor),
orders: make(map[*Scope]int),
params: pl,
results: rl,
s: s,
callback: opts.Callback,
}
return n, nil
}
func (n *decoratorNode) Call(s containerStore) (err error) {
if n.state == decoratorCalled {
return nil
}
n.state = decoratorOnStack
if err := shallowCheckDependencies(s, n.params); err != nil {
return errMissingDependencies{
Func: n.location,
Reason: err,
}
}
args, err := n.params.BuildList(n.s)
if err != nil {
return errArgumentsFailed{
Func: n.location,
Reason: err,
}
}
if n.callback != nil {
// Wrap in separate func to include PanicErrors
defer func() {
n.callback(CallbackInfo{
Name: fmt.Sprintf("%v.%v", n.location.Package, n.location.Name),
Error: err,
})
}()
}
if n.s.recoverFromPanics {
defer func() {
if p := recover(); p != nil {
err = PanicError{
fn: n.location,
Panic: p,
}
}
}()
}
results := s.invoker()(reflect.ValueOf(n.dcor), args)
if err = n.results.ExtractList(n.s, true /* decorated */, results); err != nil {
return err
}
n.state = decoratorCalled
return nil
}
func (n *decoratorNode) ID() dot.CtorID { return n.id }
func (n *decoratorNode) State() decoratorState { return n.state }
// DecorateOption modifies the default behavior of Decorate.
type DecorateOption interface {
apply(*decorateOptions)
}
type decorateOptions struct {
Info *DecorateInfo
Callback Callback
}
// FillDecorateInfo is a DecorateOption that writes info on what Dig was
// able to get out of the provided decorator into the provided DecorateInfo.
func FillDecorateInfo(info *DecorateInfo) DecorateOption {
return fillDecorateInfoOption{info: info}
}
type fillDecorateInfoOption struct{ info *DecorateInfo }
func (o fillDecorateInfoOption) String() string {
return fmt.Sprintf("FillDecorateInfo(%p)", o.info)
}
func (o fillDecorateInfoOption) apply(opts *decorateOptions) {
opts.Info = o.info
}
// DecorateInfo provides information about the decorator's inputs and outputs
// types as strings, as well as the ID of the decorator supplied to the Container.
type DecorateInfo struct {
ID ID
Inputs []*Input
Outputs []*Output
}
// Decorate provides a decorator for a type that has already been provided in the Container.
// Decorations at this level affect all scopes of the container.
// See Scope.Decorate for information on how to use this method.
func (c *Container) Decorate(decorator interface{}, opts ...DecorateOption) error {
return c.scope.Decorate(decorator, opts...)
}
// Decorate provides a decorator for a type that has already been provided in the Scope.
//
// Similar to Provide, Decorate takes in a function with zero or more dependencies and one
// or more results. Decorate can be used to modify a type that was already introduced to the
// Scope, or completely replace it with a new object.
//
// For example,
//
// s.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// })
//
// This takes in a value, augments it with a name, and returns a replacement for it. Functions
// in the Scope's dependency graph that use *zap.Logger will now use the *zap.Logger
// returned by this decorator.
//
// A decorator can also take in multiple parameters and replace one of them:
//
// s.Decorate(func(log *zap.Logger, cfg *Config) *zap.Logger {
// return log.Named(cfg.Name)
// })
//
// Or replace a subset of them:
//
// s.Decorate(func(
// log *zap.Logger,
// cfg *Config,
// scope metrics.Scope
// ) (*zap.Logger, metrics.Scope) {
// log = log.Named(cfg.Name)
// scope = scope.With(metrics.Tag("service", cfg.Name))
// return log, scope
// })
//
// Decorating a Scope affects all the child scopes of this Scope.
//
// Similar to a provider, the decorator function gets called *at most once*.
func (s *Scope) Decorate(decorator interface{}, opts ...DecorateOption) error {
var options decorateOptions
for _, opt := range opts {
opt.apply(&options)
}
dn, err := newDecoratorNode(decorator, s, options)
if err != nil {
return err
}
keys, err := findResultKeys(dn.results)
if err != nil {
return err
}
for _, k := range keys {
if _, ok := s.decorators[k]; ok {
return newErrInvalidInput(
fmt.Sprintf("cannot decorate using function %v: %s already decorated", dn.dtype, k), nil)
}
s.decorators[k] = dn
}
if info := options.Info; info != nil {
params := dn.params.DotParam()
results := dn.results.DotResult()
info.ID = (ID)(dn.id)
info.Inputs = make([]*Input, len(params))
info.Outputs = make([]*Output, len(results))
for i, param := range params {
info.Inputs[i] = &Input{
t: param.Type,
optional: param.Optional,
name: param.Name,
group: param.Group,
}
}
for i, res := range results {
info.Outputs[i] = &Output{
t: res.Type,
name: res.Name,
group: res.Group,
}
}
}
return nil
}
func findResultKeys(r resultList) ([]key, error) {
// use BFS to search for all keys included in a resultList.
var (
q []result
keys []key
)
q = append(q, r)
for len(q) > 0 {
res := q[0]
q = q[1:]
switch innerResult := res.(type) {
case resultSingle:
keys = append(keys, key{t: innerResult.Type, name: innerResult.Name})
case resultGrouped:
if innerResult.Type.Kind() != reflect.Slice {
return nil, newErrInvalidInput("decorating a value group requires decorating the entire value group, not a single value", nil)
}
keys = append(keys, key{t: innerResult.Type.Elem(), group: innerResult.Group})
case resultObject:
for _, f := range innerResult.Fields {
q = append(q, f.Result)
}
case resultList:
q = append(q, innerResult.Results...)
}
}
return keys, nil
}

348
vendor/go.uber.org/dig/doc.go generated vendored Normal file
View File

@@ -0,0 +1,348 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package dig provides an opinionated way of resolving object dependencies.
//
// # Status
//
// STABLE. No breaking changes will be made in this major version.
//
// # Container
//
// Dig exposes type Container as an object capable of resolving a directed
// acyclic dependency graph. Use the New function to create one.
//
// c := dig.New()
//
// # Provide
//
// Constructors for different types are added to the container by using the
// Provide method. A constructor can declare a dependency on another type by
// simply adding it as a function parameter. Dependencies for a type can be
// added to the graph both, before and after the type was added.
//
// err := c.Provide(func(conn *sql.DB) (*UserGateway, error) {
// // ...
// })
// if err != nil {
// // ...
// }
//
// if err := c.Provide(newDBConnection); err != nil {
// // ...
// }
//
// Multiple constructors can rely on the same type. The container creates a
// singleton for each retained type, instantiating it at most once when
// requested directly or as a dependency of another type.
//
// err := c.Provide(func(conn *sql.DB) *CommentGateway {
// // ...
// })
// if err != nil {
// // ...
// }
//
// Constructors can declare any number of dependencies as parameters and
// optionally, return errors.
//
// err := c.Provide(func(u *UserGateway, c *CommentGateway) (*RequestHandler, error) {
// // ...
// })
// if err != nil {
// // ...
// }
//
// if err := c.Provide(newHTTPServer); err != nil {
// // ...
// }
//
// Constructors can also return multiple results to add multiple types to the
// container.
//
// err := c.Provide(func(conn *sql.DB) (*UserGateway, *CommentGateway, error) {
// // ...
// })
// if err != nil {
// // ...
// }
//
// Constructors that accept a variadic number of arguments are treated as if
// they don't have those arguments. That is,
//
// func NewVoteGateway(db *sql.DB, options ...Option) *VoteGateway
//
// Is treated the same as,
//
// func NewVoteGateway(db *sql.DB) *VoteGateway
//
// The constructor will be called with all other dependencies and no variadic
// arguments.
//
// # Invoke
//
// Types added to the container may be consumed by using the Invoke method.
// Invoke accepts any function that accepts one or more parameters and
// optionally, returns an error. Dig calls the function with the requested
// type, instantiating only those types that were requested by the function.
// The call fails if any type or its dependencies (both direct and transitive)
// were not available in the container.
//
// err := c.Invoke(func(l *log.Logger) {
// // ...
// })
// if err != nil {
// // ...
// }
//
// err := c.Invoke(func(server *http.Server) error {
// // ...
// })
// if err != nil {
// // ...
// }
//
// Any error returned by the invoked function is propagated back to the
// caller.
//
// # Parameter Objects
//
// Constructors declare their dependencies as function parameters. This can
// very quickly become unreadable if the constructor has a lot of
// dependencies.
//
// func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
// // ...
// }
//
// A pattern employed to improve readability in a situation like this is to
// create a struct that lists all the parameters of the function as fields and
// changing the function to accept that struct instead. This is referred to as
// a parameter object.
//
// Dig has first class support for parameter objects: any struct embedding
// dig.In gets treated as a parameter object. The following is equivalent to
// the constructor above.
//
// type HandlerParams struct {
// dig.In
//
// Users *UserGateway
// Comments *CommentGateway
// Posts *PostGateway
// Votes *VoteGateway
// AuthZ *AuthZGateway
// }
//
// func NewHandler(p HandlerParams) *Handler {
// // ...
// }
//
// Handlers can receive any combination of parameter objects and parameters.
//
// func NewHandler(p HandlerParams, l *log.Logger) *Handler {
// // ...
// }
//
// # Result Objects
//
// Result objects are the flip side of parameter objects. These are structs
// that represent multiple outputs from a single function as fields in the
// struct. Structs embedding dig.Out get treated as result objects.
//
// func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
// // ...
// }
//
// The above is equivalent to,
//
// type Gateways struct {
// dig.Out
//
// Users *UserGateway
// Comments *CommentGateway
// Posts *PostGateway
// }
//
// func SetupGateways(conn *sql.DB) (Gateways, error) {
// // ...
// }
//
// # Optional Dependencies
//
// Constructors often don't have a hard dependency on some types and
// are able to operate in a degraded state when that dependency is missing.
// Dig supports declaring dependencies as optional by adding an
// `optional:"true"` tag to fields of a dig.In struct.
//
// Fields in a dig.In structs that have the `optional:"true"` tag are treated
// as optional by Dig.
//
// type UserGatewayParams struct {
// dig.In
//
// Conn *sql.DB
// Cache *redis.Client `optional:"true"`
// }
//
// If an optional field is not available in the container, the constructor
// will receive a zero value for the field.
//
// func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
// if p.Cache == nil {
// log.Print("Caching disabled")
// }
// // ...
// }
//
// Constructors that declare dependencies as optional MUST handle the case of
// those dependencies being absent.
//
// The optional tag also allows adding new dependencies without breaking
// existing consumers of the constructor.
//
// # Named Values
//
// Some use cases call for multiple values of the same type. Dig allows adding
// multiple values of the same type to the container with the use of Named
// Values.
//
// Named Values can be produced by passing the dig.Name option when a
// constructor is provided. All values produced by that constructor will have
// the given name.
//
// Given the following constructors,
//
// func NewReadOnlyConnection(...) (*sql.DB, error)
// func NewReadWriteConnection(...) (*sql.DB, error)
//
// You can provide *sql.DB into a Container under different names by passing
// the dig.Name option.
//
// c.Provide(NewReadOnlyConnection, dig.Name("ro"))
// c.Provide(NewReadWriteConnection, dig.Name("rw"))
//
// Alternatively, you can produce a dig.Out struct and tag its fields with
// `name:".."` to have the corresponding value added to the graph under the
// specified name.
//
// type ConnectionResult struct {
// dig.Out
//
// ReadWrite *sql.DB `name:"rw"`
// ReadOnly *sql.DB `name:"ro"`
// }
//
// func ConnectToDatabase(...) (ConnectionResult, error) {
// // ...
// return ConnectionResult{ReadWrite: rw, ReadOnly: ro}, nil
// }
//
// Regardless of how a Named Value was produced, it can be consumed by another
// constructor by accepting a dig.In struct which has exported fields with the
// same name AND type that you provided.
//
// type GatewayParams struct {
// dig.In
//
// WriteToConn *sql.DB `name:"rw"`
// ReadFromConn *sql.DB `name:"ro"`
// }
//
// The name tag may be combined with the optional tag to declare the
// dependency optional.
//
// type GatewayParams struct {
// dig.In
//
// WriteToConn *sql.DB `name:"rw"`
// ReadFromConn *sql.DB `name:"ro" optional:"true"`
// }
//
// func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
// if p.ReadFromConn == nil {
// log.Print("Warning: Using RW connection for reads")
// p.ReadFromConn = p.WriteToConn
// }
// // ...
// }
//
// # Value Groups
//
// Added in Dig 1.2.
//
// Dig provides value groups to allow producing and consuming many values of
// the same type. Value groups allow constructors to send values to a named,
// unordered collection in the container. Other constructors can request all
// values in this collection as a slice.
//
// Constructors can send values into value groups by returning a dig.Out
// struct tagged with `group:".."`.
//
// type HandlerResult struct {
// dig.Out
//
// Handler Handler `group:"server"`
// }
//
// func NewHelloHandler() HandlerResult {
// ..
// }
//
// func NewEchoHandler() HandlerResult {
// ..
// }
//
// Any number of constructors may provide values to this named collection.
// Other constructors can request all values for this collection by requesting
// a slice tagged with `group:".."`. This will execute all constructors that
// provide a value to that group in an unspecified order.
//
// type ServerParams struct {
// dig.In
//
// Handlers []Handler `group:"server"`
// }
//
// func NewServer(p ServerParams) *Server {
// server := newServer()
// for _, h := range p.Handlers {
// server.Register(h)
// }
// return server
// }
//
// Note that values in a value group are unordered. Dig makes no guarantees
// about the order in which these values will be produced.
//
// Value groups can be used to provide multiple values for a group from a
// dig.Out using slices, however considering groups are retrieved by requesting
// a slice this implies that the values must be retrieved using a slice of
// slices. As of dig v1.9.0, if you want to provide individual elements to the
// group instead of the slice itself, you can add the `flatten` modifier to the
// group from a dig.Out.
//
// type IntResult struct {
// dig.Out
//
// Handler []int `group:"server"` // [][]int from dig.In
// Handler []int `group:"server,flatten"` // []int from dig.In
// }
package dig // import "go.uber.org/dig"

527
vendor/go.uber.org/dig/error.go generated vendored Normal file
View File

@@ -0,0 +1,527 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"errors"
"fmt"
"io"
"reflect"
"sort"
"go.uber.org/dig/internal/digreflect"
"go.uber.org/dig/internal/dot"
)
// Error is an interface implemented by all Dig errors.
//
// Use this interface, in conjunction with [RootCause], in order to
// determine if errors you encounter come from Dig, or if they come
// from provided constructors or invoked functions. See [RootCause]
// for more info.
type Error interface {
error
// Writes the message or context for this error in the chain.
//
// Note: the Error interface must always have a private function
// such as this one in order to maintain properly sealed.
//
// verb is either %v or %+v.
writeMessage(w io.Writer, v string)
}
// a digError is a dig.Error with additional functionality for
// internal use - namely the ability to be formatted.
type digError interface {
Error
fmt.Formatter
}
// A PanicError occurs when a panic occurs while running functions given to the container
// with the [RecoverFromPanic] option being set. It contains the panic message from the
// original panic. A PanicError does not wrap other errors, and it does not implement
// dig.Error, meaning it will be returned from [RootCause]. With the [RecoverFromPanic]
// option set, a panic can be distinguished from dig errors and errors from provided/
// invoked/decorated functions like so:
//
// rootCause := dig.RootCause(err)
//
// var pe dig.PanicError
// var de dig.Error
// if errors.As(rootCause, &pe) {
// // This is caused by a panic
// } else if errors.As(err, &de) {
// // This is a dig error
// } else {
// // This is an error from one of my provided/invoked functions or decorators
// }
//
// Or, if only interested in distinguishing panics from errors:
//
// var pe dig.PanicError
// if errors.As(err, &pe) {
// // This is caused by a panic
// } else {
// // This is an error
// }
type PanicError struct {
// The function the panic occurred at
fn *digreflect.Func
// The panic that was returned from recover()
Panic any
}
// Format will format the PanicError, expanding the corresponding function if in +v mode.
func (e PanicError) Format(w fmt.State, c rune) {
if w.Flag('+') && c == 'v' {
fmt.Fprintf(w, "panic: %q in func: %+v", e.Panic, e.fn)
} else {
fmt.Fprintf(w, "panic: %q in func: %v", e.Panic, e.fn)
}
}
func (e PanicError) Error() string {
return fmt.Sprint(e)
}
// formatError will call a dig.Error's writeMessage() method to print the error message
// and then will automatically attempt to print errors wrapped underneath (which can create
// a recursive effect if the wrapped error's Format() method then points back to this function).
func formatError(e digError, w fmt.State, v rune) {
multiline := w.Flag('+') && v == 'v'
verb := "%v"
if multiline {
verb = "%+v"
}
// "context: " or "context:\n"
e.writeMessage(w, verb)
// Will route back to this function recursively if next error
// is also wrapped and points back here
wrappedError := errors.Unwrap(e)
if wrappedError == nil {
return
}
io.WriteString(w, ":")
if multiline {
io.WriteString(w, "\n")
} else {
io.WriteString(w, " ")
}
fmt.Fprintf(w, verb, wrappedError)
}
// RootCause returns the first non-dig.Error in a chain of wrapped
// errors, if there is one. Otherwise, RootCause returns the error
// on the bottom of the chain of wrapped errors.
//
// Use this function and errors.As to differentiate between Dig errors
// and errors thrown by provided constructors or invoked functions:
//
// rootCause := dig.RootCause(err)
// var de dig.Error
// if errors.As(rootCause, &de) {
// // Is a Dig error
// } else {
// // Is an error thrown by one of my provided/invoked/decorated functions
// }
//
// See [PanicError] for an example showing how to additionally detect
// and handle panics in provided/invoked/decorated functions.
func RootCause(err error) error {
var de Error
// Dig down to first non dig.Error, or bottom of chain
for ; errors.As(err, &de); err = errors.Unwrap(de) {
}
if err == nil {
return de
}
return err
}
// errInvalidInput is returned whenever the user provides bad input when
// interacting with the container. May optionally have a more detailed
// error wrapped underneath.
type errInvalidInput struct {
Message string
Cause error
}
var _ digError = errInvalidInput{}
// newErrInvalidInput creates a new errInvalidInput, wrapping the given
// other error that caused this error. If there is no underlying cause,
// pass in nil. This will cause all attempts to unwrap this error to return
// nil, replicating errors.Unwrap's behavior when passed an error without
// an Unwrap() method.
func newErrInvalidInput(msg string, cause error) errInvalidInput {
return errInvalidInput{msg, cause}
}
func (e errInvalidInput) Error() string { return fmt.Sprint(e) }
func (e errInvalidInput) Unwrap() error { return e.Cause }
func (e errInvalidInput) writeMessage(w io.Writer, _ string) {
fmt.Fprintf(w, e.Message)
}
func (e errInvalidInput) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
// errProvide is returned when a constructor could not be Provided into the
// container.
type errProvide struct {
Func *digreflect.Func
Reason error
}
var _ digError = errProvide{}
func (e errProvide) Error() string { return fmt.Sprint(e) }
func (e errProvide) Unwrap() error { return e.Reason }
func (e errProvide) writeMessage(w io.Writer, verb string) {
fmt.Fprintf(w, "cannot provide function "+verb, e.Func)
}
func (e errProvide) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
// errConstructorFailed is returned when a user-provided constructor failed
// with a non-nil error.
type errConstructorFailed struct {
Func *digreflect.Func
Reason error
}
var _ digError = errConstructorFailed{}
func (e errConstructorFailed) Error() string { return fmt.Sprint(e) }
func (e errConstructorFailed) Unwrap() error { return e.Reason }
func (e errConstructorFailed) writeMessage(w io.Writer, verb string) {
fmt.Fprintf(w, "received non-nil error from function "+verb, e.Func)
}
func (e errConstructorFailed) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
// errArgumentsFailed is returned when a function could not be run because one
// of its dependencies failed to build for any reason.
type errArgumentsFailed struct {
Func *digreflect.Func
Reason error
}
var _ digError = errArgumentsFailed{}
func (e errArgumentsFailed) Error() string { return fmt.Sprint(e) }
func (e errArgumentsFailed) Unwrap() error { return e.Reason }
func (e errArgumentsFailed) writeMessage(w io.Writer, verb string) {
fmt.Fprintf(w, "could not build arguments for function "+verb, e.Func)
}
func (e errArgumentsFailed) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
// errMissingDependencies is returned when the dependencies of a function are
// not available in the container.
type errMissingDependencies struct {
Func *digreflect.Func
Reason error
}
var _ digError = errMissingDependencies{}
func (e errMissingDependencies) Error() string { return fmt.Sprint(e) }
func (e errMissingDependencies) Unwrap() error { return e.Reason }
func (e errMissingDependencies) writeMessage(w io.Writer, verb string) {
fmt.Fprintf(w, "missing dependencies for function "+verb, e.Func)
}
func (e errMissingDependencies) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
// errParamSingleFailed is returned when a paramSingle could not be built.
type errParamSingleFailed struct {
Key key
Reason error
CtorID dot.CtorID
}
var _ digError = errParamSingleFailed{}
func (e errParamSingleFailed) Error() string { return fmt.Sprint(e) }
func (e errParamSingleFailed) Unwrap() error { return e.Reason }
func (e errParamSingleFailed) writeMessage(w io.Writer, _ string) {
fmt.Fprintf(w, "failed to build %v", e.Key)
}
func (e errParamSingleFailed) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
func (e errParamSingleFailed) updateGraph(g *dot.Graph) {
failed := &dot.Result{
Node: &dot.Node{
Name: e.Key.name,
Group: e.Key.group,
Type: e.Key.t,
},
}
g.FailNodes([]*dot.Result{failed}, e.CtorID)
}
// errParamGroupFailed is returned when a value group cannot be built because
// any of the values in the group failed to build.
type errParamGroupFailed struct {
Key key
Reason error
CtorID dot.CtorID
}
var _ digError = errParamGroupFailed{}
func (e errParamGroupFailed) Error() string { return fmt.Sprint(e) }
func (e errParamGroupFailed) Unwrap() error { return e.Reason }
func (e errParamGroupFailed) writeMessage(w io.Writer, _ string) {
fmt.Fprintf(w, "could not build value group %v", e.Key)
}
func (e errParamGroupFailed) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
func (e errParamGroupFailed) updateGraph(g *dot.Graph) {
g.FailGroupNodes(e.Key.group, e.Key.t, e.CtorID)
}
// missingType holds information about a type that was missing in the
// container.
type missingType struct {
Key key // item that was missing
// If non-empty, we will include suggestions for what the user may have
// meant.
suggestions []key
}
// Format prints a string representation of missingType.
//
// With %v, it prints a short representation ideal for an itemized list.
//
// io.Writer
// io.Writer: did you mean *bytes.Buffer?
// io.Writer: did you mean *bytes.Buffer, or *os.File?
//
// With %+v, it prints a longer representation ideal for standalone output.
//
// io.Writer: did you mean to Provide it?
// io.Writer: did you mean to use *bytes.Buffer?
// io.Writer: did you mean to use one of *bytes.Buffer, or *os.File?
func (mt missingType) Format(w fmt.State, v rune) {
plusV := w.Flag('+') && v == 'v'
fmt.Fprint(w, mt.Key)
switch len(mt.suggestions) {
case 0:
if plusV {
io.WriteString(w, " (did you mean to Provide it?)")
}
case 1:
sug := mt.suggestions[0]
if plusV {
fmt.Fprintf(w, " (did you mean to use %v?)", sug)
} else {
fmt.Fprintf(w, " (did you mean %v?)", sug)
}
default:
if plusV {
io.WriteString(w, " (did you mean to use one of ")
} else {
io.WriteString(w, " (did you mean ")
}
lastIdx := len(mt.suggestions) - 1
for i, sug := range mt.suggestions {
if i > 0 {
io.WriteString(w, ", ")
if i == lastIdx {
io.WriteString(w, "or ")
}
}
fmt.Fprint(w, sug)
}
io.WriteString(w, "?)")
}
}
// errMissingType is returned when one or more values that were expected in
// the container were not available.
//
// Multiple instances of this error may be merged together by appending them.
type errMissingTypes []missingType // inv: len > 0
var _ digError = errMissingTypes(nil)
func newErrMissingTypes(c containerStore, k key) errMissingTypes {
// Possible types we will look for in the container. We will always look
// for pointers to the requested type and some extras on a per-Kind basis.
suggestions := []reflect.Type{reflect.PtrTo(k.t)}
if k.t.Kind() == reflect.Ptr {
// The user requested a pointer but maybe we have a value.
suggestions = append(suggestions, k.t.Elem())
}
if k.t.Kind() == reflect.Slice {
// Maybe the user meant a slice of pointers while we have the slice of elements
suggestions = append(suggestions, reflect.SliceOf(reflect.PtrTo(k.t.Elem())))
// Maybe the user meant a slice of elements while we have the slice of pointers
sliceElement := k.t.Elem()
if sliceElement.Kind() == reflect.Ptr {
suggestions = append(suggestions, reflect.SliceOf(sliceElement.Elem()))
}
}
if k.t.Kind() == reflect.Array {
// Maybe the user meant an array of pointers while we have the array of elements
suggestions = append(suggestions, reflect.ArrayOf(k.t.Len(), reflect.PtrTo(k.t.Elem())))
// Maybe the user meant an array of elements while we have the array of pointers
arrayElement := k.t.Elem()
if arrayElement.Kind() == reflect.Ptr {
suggestions = append(suggestions, reflect.ArrayOf(k.t.Len(), arrayElement.Elem()))
}
}
knownTypes := c.knownTypes()
if k.t.Kind() == reflect.Interface {
// Maybe we have an implementation of the interface.
for _, t := range knownTypes {
if t.Implements(k.t) {
suggestions = append(suggestions, t)
}
}
} else {
// Maybe we have an interface that this type implements.
for _, t := range knownTypes {
if t.Kind() == reflect.Interface {
if k.t.Implements(t) {
suggestions = append(suggestions, t)
}
}
}
}
// range through c.providers is non-deterministic. Let's sort the list of
// suggestions.
sort.Sort(byTypeName(suggestions))
mt := missingType{Key: k}
for _, t := range suggestions {
if len(c.getValueProviders(k.name, t)) > 0 {
k.t = t
mt.suggestions = append(mt.suggestions, k)
}
}
return errMissingTypes{mt}
}
func (e errMissingTypes) Error() string { return fmt.Sprint(e) }
func (e errMissingTypes) writeMessage(w io.Writer, v string) {
multiline := v == "%+v"
if len(e) == 1 {
io.WriteString(w, "missing type:")
} else {
io.WriteString(w, "missing types:")
}
if !multiline {
// With %v, we need a space between : since the error
// won't be on a new line.
io.WriteString(w, " ")
}
for i, mt := range e {
if multiline {
io.WriteString(w, "\n\t- ")
} else if i > 0 {
io.WriteString(w, "; ")
}
if multiline {
fmt.Fprintf(w, "%+v", mt)
} else {
fmt.Fprintf(w, "%v", mt)
}
}
}
func (e errMissingTypes) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
func (e errMissingTypes) updateGraph(g *dot.Graph) {
missing := make([]*dot.Result, len(e))
for i, mt := range e {
missing[i] = &dot.Result{
Node: &dot.Node{
Name: mt.Key.name,
Group: mt.Key.group,
Type: mt.Key.t,
},
}
}
g.AddMissingNodes(missing)
}
type errVisualizer interface {
updateGraph(*dot.Graph)
}

7
vendor/go.uber.org/dig/glide.yaml generated vendored Normal file
View File

@@ -0,0 +1,7 @@
package: go.uber.org/dig
license: MIT
testImport:
- package: github.com/stretchr/testify
subpackages:
- assert
- require

115
vendor/go.uber.org/dig/graph.go generated vendored Normal file
View File

@@ -0,0 +1,115 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import "go.uber.org/dig/internal/graph"
// graphNode is a single node in the dependency graph.
type graphNode struct {
Wrapped interface{}
}
// graphHolder is the dependency graph of the container.
// It saves constructorNodes and paramGroupedSlice (value groups)
// as nodes in the graph.
// It implements the graph interface defined by internal/graph.
// It has 1-1 correspondence with the Scope whose graph it represents.
type graphHolder struct {
// all the nodes defined in the graph.
nodes []*graphNode
// Scope whose graph this holder contains.
s *Scope
// Number of nodes in the graph at last snapshot.
// -1 if no snapshot has been taken.
snap int
}
var _ graph.Graph = (*graphHolder)(nil)
func newGraphHolder(s *Scope) *graphHolder {
return &graphHolder{s: s, snap: -1}
}
func (gh *graphHolder) Order() int { return len(gh.nodes) }
// EdgesFrom returns the indices of nodes that are dependencies of node u.
//
// To do that, it needs to do one of the following:
//
// For constructor nodes, it retrieves the providers of the constructor's
// parameters from the container and reports their orders.
//
// For value group nodes, it retrieves the group providers from the container
// and reports their orders.
func (gh *graphHolder) EdgesFrom(u int) []int {
var orders []int
switch w := gh.Lookup(u).(type) {
case *constructorNode:
for _, param := range w.paramList.Params {
orders = append(orders, getParamOrder(gh, param)...)
}
case *paramGroupedSlice:
providers := gh.s.getAllGroupProviders(w.Group, w.Type.Elem())
for _, provider := range providers {
orders = append(orders, provider.Order(gh.s))
}
}
return orders
}
// NewNode adds a new value to the graph and returns its order.
func (gh *graphHolder) NewNode(wrapped interface{}) int {
order := len(gh.nodes)
gh.nodes = append(gh.nodes, &graphNode{
Wrapped: wrapped,
})
return order
}
// Lookup retrieves the value for the node with the given order.
// Lookup panics if i is invalid.
func (gh *graphHolder) Lookup(i int) interface{} {
return gh.nodes[i].Wrapped
}
// Snapshot takes a temporary snapshot of the current state of the graph.
// Use with Rollback to undo changes to the graph.
//
// Only one snapshot is allowed at a time.
// Multiple calls to snapshot will overwrite prior snapshots.
func (gh *graphHolder) Snapshot() {
gh.snap = len(gh.nodes)
}
// Rollback rolls back a snapshot to a previously captured state.
// This is a no-op if no snapshot was captured.
func (gh *graphHolder) Rollback() {
if gh.snap < 0 {
return
}
// nodes is an append-only list. To rollback, we just drop the
// extraneous entries from the slice.
gh.nodes = gh.nodes[:gh.snap]
gh.snap = -1
}

67
vendor/go.uber.org/dig/group.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"io"
"strings"
)
const (
_groupTag = "group"
)
type group struct {
Name string
Flatten bool
Soft bool
}
type errInvalidGroupOption struct{ Option string }
var _ digError = errInvalidGroupOption{}
func (e errInvalidGroupOption) Error() string { return fmt.Sprint(e) }
func (e errInvalidGroupOption) writeMessage(w io.Writer, v string) {
fmt.Fprintf(w, "invalid option %q", e.Option)
}
func (e errInvalidGroupOption) Format(w fmt.State, c rune) {
formatError(e, w, c)
}
func parseGroupString(s string) (group, error) {
components := strings.Split(s, ",")
g := group{Name: components[0]}
for _, c := range components[1:] {
switch c {
case "flatten":
g.Flatten = true
case "soft":
g.Soft = true
default:
return g, errInvalidGroupOption{Option: c}
}
}
return g, nil
}

175
vendor/go.uber.org/dig/inout.go generated vendored Normal file
View File

@@ -0,0 +1,175 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"container/list"
"fmt"
"reflect"
"strconv"
)
var (
_noValue reflect.Value
_errType = reflect.TypeOf((*error)(nil)).Elem()
_inPtrType = reflect.TypeOf((*In)(nil))
_inType = reflect.TypeOf(In{})
_outPtrType = reflect.TypeOf((*Out)(nil))
_outType = reflect.TypeOf(Out{})
)
// Placeholder type placed in dig.In/dig.out to make their special nature
// obvious in godocs.
// Otherwise they will appear as plain empty structs.
type digSentinel struct{}
// In may be embedded into structs to request dig to treat them as special
// parameter structs. When a constructor accepts such a struct, instead of the
// struct becoming a dependency for that constructor, all its fields become
// dependencies instead. See the section on Parameter Objects in the
// package-level documentation for more information.
//
// Fields of the struct may optionally be tagged to customize the behavior of
// dig. The following tags are supported,
//
// name Requests a value with the same name and type from the
// container. See Named Values for more information.
// optional If set to true, indicates that the dependency is optional and
// the constructor gracefully handles its absence.
// group Name of the Value Group from which this field will be filled.
// The field must be a slice type. See Value Groups in the
// package documentation for more information.
type In struct{ _ digSentinel }
// Out is an embeddable type that signals to dig that the returned
// struct should be treated differently. Instead of the struct itself
// becoming part of the container, all members of the struct will.
// Out may be embedded into structs to request dig to treat them as special
// result structs. When a constructor returns such a struct, instead of the
// struct becoming a result of the constructor, all its fields become results
// of the constructor. See the section on Result Objects in the package-level
// documentation for more information.
//
// Fields of the struct may optionally be tagged to customize the behavior of
// dig. The following tags are supported,
//
// name Specifies the name of the value. Only a field on a dig.In
// struct with the same 'name' annotation can receive this
// value. See Named Values for more information.
// group Name of the Value Group to which this field's value is being
// sent. See Value Groups in the package documentation for more
// information.
type Out struct{ _ digSentinel }
func isError(t reflect.Type) bool {
return t.Implements(_errType)
}
// IsIn checks whether the given struct is a dig.In struct. A struct qualifies
// as a dig.In struct if it embeds the dig.In type or if any struct that it
// embeds is a dig.In struct. The parameter may be the reflect.Type of the
// struct rather than the struct itself.
//
// A struct MUST qualify as a dig.In struct for its fields to be treated
// specially by dig.
//
// See the documentation for dig.In for a comprehensive list of supported
// tags.
func IsIn(o interface{}) bool {
return embedsType(o, _inType)
}
// IsOut checks whether the given struct is a dig.Out struct. A struct
// qualifies as a dig.Out struct if it embeds the dig.Out type or if any
// struct that it embeds is a dig.Out struct. The parameter may be the
// reflect.Type of the struct rather than the struct itself.
//
// A struct MUST qualify as a dig.Out struct for its fields to be treated
// specially by dig.
//
// See the documentation for dig.Out for a comprehensive list of supported
// tags.
func IsOut(o interface{}) bool {
return embedsType(o, _outType)
}
// Returns true if t embeds e or if any of the types embedded by t embed e.
func embedsType(i interface{}, e reflect.Type) bool {
// TODO: this function doesn't consider e being a pointer.
// given `type A foo { *In }`, this function would return false for
// embedding dig.In, which makes for some extra error checking in places
// that call this function. Might be worthwhile to consider reflect.Indirect
// usage to clean up the callers.
if i == nil {
return false
}
// maybe it's already a reflect.Type
t, ok := i.(reflect.Type)
if !ok {
// take the type if it's not
t = reflect.TypeOf(i)
}
// We are going to do a breadth-first search of all embedded fields.
types := list.New()
types.PushBack(t)
for types.Len() > 0 {
t := types.Remove(types.Front()).(reflect.Type)
if t == e {
return true
}
if t.Kind() != reflect.Struct {
continue
}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.Anonymous {
types.PushBack(f.Type)
}
}
}
// If perf is an issue, we can cache known In objects and Out objects in a
// map[reflect.Type]struct{}.
return false
}
// Checks if a field of an In struct is optional.
func isFieldOptional(f reflect.StructField) (bool, error) {
tag := f.Tag.Get(_optionalTag)
if tag == "" {
return false, nil
}
optional, err := strconv.ParseBool(tag)
if err != nil {
err = newErrInvalidInput(
fmt.Sprintf("invalid value %q for %q tag on field %v", tag, _optionalTag, f.Name), err)
}
return optional, err
}

34
vendor/go.uber.org/dig/internal/digerror/errors.go generated vendored Normal file
View File

@@ -0,0 +1,34 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package digerror
import (
"fmt"
)
// BugPanicf panics with the provided message directing users to GitHub issues
// creation page.
func BugPanicf(msg string, args ...interface{}) {
panic(fmt.Sprintf("It looks like you have found a bug in dig. "+
"Please file an issue at https://github.com/uber-go/dig/issues/new "+
"and provide the following message: "+
msg, args...))
}

125
vendor/go.uber.org/dig/internal/digreflect/func.go generated vendored Normal file
View File

@@ -0,0 +1,125 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package digreflect
import (
"fmt"
"net/url"
"reflect"
"runtime"
"strings"
)
// Func contains runtime information about a function.
type Func struct {
// Name of the function.
Name string
// Name of the package in which this function is defined.
Package string
// Path to the file in which this function is defined.
File string
// Line number in the file at which this function is defined.
Line int
}
// String returns a string representation of the function.
func (f *Func) String() string {
return fmt.Sprint(f)
}
// Format implements fmt.Formatter for Func, printing a single-line
// representation for %v and a multi-line one for %+v.
func (f *Func) Format(w fmt.State, c rune) {
if w.Flag('+') && c == 'v' {
// "path/to/package".MyFunction
// path/to/file.go:42
fmt.Fprintf(w, "%q.%v", f.Package, f.Name)
fmt.Fprintf(w, "\n\t%v:%v", f.File, f.Line)
} else {
// "path/to/package".MyFunction (path/to/file.go:42)
fmt.Fprintf(w, "%q.%v (%v:%v)", f.Package, f.Name, f.File, f.Line)
}
}
// InspectFunc inspects and returns runtime information about the given
// function.
func InspectFunc(function interface{}) *Func {
fptr := reflect.ValueOf(function).Pointer()
return InspectFuncPC(fptr)
}
// InspectFuncPC inspects and returns runtime information about the function
// at the given program counter address.
func InspectFuncPC(pc uintptr) *Func {
f := runtime.FuncForPC(pc)
if f == nil {
return nil
}
pkgName, funcName := splitFuncName(f.Name())
fileName, lineNum := f.FileLine(pc)
return &Func{
Name: funcName,
Package: pkgName,
File: fileName,
Line: lineNum,
}
}
const _vendor = "/vendor/"
func splitFuncName(function string) (pname string, fname string) {
if len(function) == 0 {
return
}
// We have something like "path.to/my/pkg.MyFunction". If the function is
// a closure, it is something like, "path.to/my/pkg.MyFunction.func1".
idx := 0
// Everything up to the first "." after the last "/" is the package name.
// Everything after the "." is the full function name.
if i := strings.LastIndex(function, "/"); i >= 0 {
idx = i
}
if i := strings.Index(function[idx:], "."); i >= 0 {
idx += i
}
pname, fname = function[:idx], function[idx+1:]
// The package may be vendored.
if i := strings.Index(pname, _vendor); i > 0 {
pname = pname[i+len(_vendor):]
}
// Package names are URL-encoded to avoid ambiguity in the case where the
// package name contains ".git". Otherwise, "foo/bar.git.MyFunction" would
// mean that "git" is the top-level function and "MyFunction" is embedded
// inside it.
if unescaped, err := url.QueryUnescape(pname); err == nil {
pname = unescaped
}
return
}

61
vendor/go.uber.org/dig/internal/dot/README.md generated vendored Normal file
View File

@@ -0,0 +1,61 @@
# Dot
The dot module generates a DOT file representation of a dependency graph.
## Interpreting the graph
The graph should be read from left to right. The leftmost node in the graph (the root node) depends
on its dependency tree to the right. An arrow from node_a to node_b in the graph means that node_b
is consumed by node_a and that node_b is a parameter of node_a. The rendered graph holds the
following kinds of nodes,
**Nodes:**
- *Constructors* [Rectangles]: Takes parameters and produces results.
- *Results* [Ovals]: Results inside a constructor are produced by that constructor. Results are consumed
directly by other constructors and/or part of a group of results.
- *Groups* [Diamonds]: Represent value groups in [fx](https://godoc.org/go.uber.org/fx). Multiple results can form a group. Any
result linked to a group by an edge are members of that group. A group is a collection of results.
Groups can also be parameters of constructors.
**Edges:**
- *Solid Arrows*: An arrow from node_a to node_b means that node_b is a parameter of node_a and that
node_a depends on node_b.
- *Dashed Arrows*: A dashed arrow from node_a to node_b represents an optional dependency that node_a
has on node_b.
**Graph Colors:**
- *Red*: Graph nodes are the root cause failures.
- *Orange*: Graph nodes are the transitive failures.
## Testing and verifying changes
Unit tests and visualize golden tests are run with
```shell
$ make test
```
You can visualize the effect of your code changes by visualizing generated test graphs as pngs.
In the dig root directory, generate the graph DOT files with respect to your latest code changes.
```shell
$ go test -generate
```
Assuming that you have [graphviz](https://www.graphviz.org/) installed and are in the testdata directory,
generate a png image representation of a graph for viewing.
```shell
$ dot -Tpng ${name_of_dot_file_in_testdata}.dot -o ${name_of_dot_file_in_testdata}.png
$ open ${name_of_dot_file_in_testdata}.png
```
## Graph Pruning
If dot.Visualize is used to visualize an error graph, non-failing nodes are pruned out of the graph
to make the error graph more readable to the user. Pruning increases readability since successful
nodes clutter the graph and do not help the user debug errors.

466
vendor/go.uber.org/dig/internal/dot/graph.go generated vendored Normal file
View File

@@ -0,0 +1,466 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dot
import (
"fmt"
"reflect"
)
// ErrorType of a constructor or group is updated when they fail to build.
type ErrorType int
const (
noError ErrorType = iota
rootCause
transitiveFailure
)
// CtorID is a unique numeric identifier for constructors.
type CtorID uintptr
// Ctor encodes a constructor provided to the container for the DOT graph.
type Ctor struct {
Name string
Package string
File string
Line int
ID CtorID
Params []*Param
GroupParams []*Group
Results []*Result
ErrorType ErrorType
}
// removeParam deletes the dependency on the provided result's nodeKey.
// This is used to prune links to results of deleted constructors.
func (c *Ctor) removeParam(k nodeKey) {
var pruned []*Param
for _, p := range c.Params {
if k != p.nodeKey() {
pruned = append(pruned, p)
}
}
c.Params = pruned
}
type nodeKey struct {
t reflect.Type
name string
group string
}
// Node is a single node in a graph and is embedded into Params and Results.
type Node struct {
Type reflect.Type
Name string
Group string
}
func (n *Node) nodeKey() nodeKey {
return nodeKey{t: n.Type, name: n.Name, group: n.Group}
}
// Param is a parameter node in the graph. Parameters are the input to constructors.
type Param struct {
*Node
Optional bool
}
// Result is a result node in the graph. Results are the output of constructors.
type Result struct {
*Node
// GroupIndex is added to differentiate grouped values from one another.
// Since grouped values have the same type and group, their Node / string
// representations are the same so we need indices to uniquely identify
// the values.
GroupIndex int
}
// Group is a group node in the graph. Group represents an fx value group.
type Group struct {
// Type is the type of values in the group.
Type reflect.Type
Name string
Results []*Result
ErrorType ErrorType
}
func (g *Group) nodeKey() nodeKey {
return nodeKey{t: g.Type, group: g.Name}
}
// TODO(rhang): Avoid linear search to discover group results that should be pruned.
func (g *Group) removeResult(r *Result) {
var pruned []*Result
for _, rg := range g.Results {
if r.GroupIndex != rg.GroupIndex {
pruned = append(pruned, rg)
}
}
g.Results = pruned
}
// Graph is the DOT-format graph in a Container.
type Graph struct {
Ctors []*Ctor
ctorMap map[CtorID]*Ctor
Groups []*Group
groupMap map[nodeKey]*Group
consumers map[nodeKey][]*Ctor
Failed *FailedNodes
}
// FailedNodes is the nodes that failed in the graph.
type FailedNodes struct {
// RootCauses is a list of the point of failures. They are the root causes
// of failed invokes and can be either missing types (not provided) or
// error types (error providing).
RootCauses []*Result
// TransitiveFailures is the list of nodes that failed to build due to
// missing/failed dependencies.
TransitiveFailures []*Result
// ctors is a collection of failed constructors IDs that are populated as the graph is
// traversed for errors.
ctors map[CtorID]struct{}
// Groups is a collection of failed groupKeys that is populated as the graph is traversed
// for errors.
groups map[nodeKey]struct{}
}
// NewGraph creates an empty graph.
func NewGraph() *Graph {
return &Graph{
ctorMap: make(map[CtorID]*Ctor),
groupMap: make(map[nodeKey]*Group),
consumers: make(map[nodeKey][]*Ctor),
Failed: &FailedNodes{
ctors: make(map[CtorID]struct{}),
groups: make(map[nodeKey]struct{}),
},
}
}
// NewGroup creates a new group with information in the groupKey.
func NewGroup(k nodeKey) *Group {
return &Group{
Type: k.t,
Name: k.group,
}
}
// AddCtor adds the constructor with paramList and resultList into the graph.
func (dg *Graph) AddCtor(c *Ctor, paramList []*Param, resultList []*Result) {
var (
params []*Param
groupParams []*Group
)
// Loop through the paramList to separate them into regular params and
// grouped params. For grouped params, we use getGroup to find the actual
// group.
for _, param := range paramList {
if param.Group == "" {
// Not a value group.
params = append(params, param)
continue
}
k := nodeKey{t: param.Type.Elem(), group: param.Group}
group := dg.getGroup(k)
groupParams = append(groupParams, group)
}
for _, result := range resultList {
// If the result is a grouped value, we want to update its GroupIndex
// and add it to the Group.
if result.Group != "" {
dg.addToGroup(result, c.ID)
}
}
c.Params = params
c.GroupParams = groupParams
c.Results = resultList
// Track which constructors consume a parameter.
for _, p := range paramList {
k := p.nodeKey()
dg.consumers[k] = append(dg.consumers[k], c)
}
dg.Ctors = append(dg.Ctors, c)
dg.ctorMap[c.ID] = c
}
func (dg *Graph) failNode(r *Result, isRootCause bool) {
if isRootCause {
dg.addRootCause(r)
} else {
dg.addTransitiveFailure(r)
}
}
// AddMissingNodes adds missing nodes to the list of failed Results in the graph.
func (dg *Graph) AddMissingNodes(results []*Result) {
// The failure(s) are root causes if there are no other failures.
isRootCause := len(dg.Failed.RootCauses) == 0
for _, r := range results {
dg.failNode(r, isRootCause)
}
}
// FailNodes adds results to the list of failed Results in the graph, and
// updates the state of the constructor with the given id accordingly.
func (dg *Graph) FailNodes(results []*Result, id CtorID) {
// This failure is the root cause if there are no other failures.
isRootCause := len(dg.Failed.RootCauses) == 0
dg.Failed.ctors[id] = struct{}{}
for _, r := range results {
dg.failNode(r, isRootCause)
}
if c, ok := dg.ctorMap[id]; ok {
if isRootCause {
c.ErrorType = rootCause
} else {
c.ErrorType = transitiveFailure
}
}
}
// FailGroupNodes finds and adds the failed grouped nodes to the list of failed
// Results in the graph, and updates the state of the group and constructor
// with the given id accordingly.
func (dg *Graph) FailGroupNodes(name string, t reflect.Type, id CtorID) {
// This failure is the root cause if there are no other failures.
isRootCause := len(dg.Failed.RootCauses) == 0
k := nodeKey{t: t, group: name}
group := dg.getGroup(k)
// If the ctor does not exist it cannot be failed.
if _, ok := dg.ctorMap[id]; !ok {
return
}
// Track which constructors and groups have failed.
dg.Failed.ctors[id] = struct{}{}
dg.Failed.groups[k] = struct{}{}
for _, r := range dg.ctorMap[id].Results {
if r.Type == t && r.Group == name {
dg.failNode(r, isRootCause)
}
}
if c, ok := dg.ctorMap[id]; ok {
if isRootCause {
group.ErrorType = rootCause
c.ErrorType = rootCause
} else {
group.ErrorType = transitiveFailure
c.ErrorType = transitiveFailure
}
}
}
// getGroup finds the group by nodeKey from the graph. If it is not available,
// a new group is created and returned.
func (dg *Graph) getGroup(k nodeKey) *Group {
g, ok := dg.groupMap[k]
if !ok {
g = NewGroup(k)
dg.groupMap[k] = g
dg.Groups = append(dg.Groups, g)
}
return g
}
// addToGroup adds a newly provided grouped result to the appropriate group.
func (dg *Graph) addToGroup(r *Result, id CtorID) {
k := nodeKey{t: r.Type, group: r.Group}
group := dg.getGroup(k)
r.GroupIndex = len(group.Results)
group.Results = append(group.Results, r)
}
// PruneSuccess removes elements from the graph that do not have failed results.
// Removing elements that do not have failing results makes the graph easier to debug,
// since non-failing nodes and edges can clutter the graph and don't help the user debug.
func (dg *Graph) PruneSuccess() {
dg.pruneCtors(dg.Failed.ctors)
dg.pruneGroups(dg.Failed.groups)
}
// pruneCtors removes constructors from the graph that do not have failing Results.
func (dg *Graph) pruneCtors(failed map[CtorID]struct{}) {
var pruned []*Ctor
for _, c := range dg.Ctors {
if _, ok := failed[c.ID]; ok {
pruned = append(pruned, c)
continue
}
// If a constructor is deleted, the constructor's stale result references need to
// be removed from that result's Group and/or consuming constructor.
dg.pruneCtorParams(c, dg.consumers)
dg.pruneGroupResults(c, dg.groupMap)
delete(dg.ctorMap, c.ID)
}
dg.Ctors = pruned
}
// pruneGroups removes groups from the graph that do not have failing results.
func (dg *Graph) pruneGroups(failed map[nodeKey]struct{}) {
var pruned []*Group
for _, g := range dg.Groups {
k := g.nodeKey()
if _, ok := failed[k]; ok {
pruned = append(pruned, g)
continue
}
delete(dg.groupMap, k)
}
dg.Groups = pruned
dg.pruneCtorGroupParams(dg.groupMap)
}
// pruneCtorParams removes results of the constructor argument that are still referenced in the
// Params of constructors that consume those results. If the results in the constructor are found
// in the params of a consuming constructor that result should be removed.
func (dg *Graph) pruneCtorParams(c *Ctor, consumers map[nodeKey][]*Ctor) {
for _, r := range c.Results {
for _, ctor := range consumers[r.nodeKey()] {
ctor.removeParam(r.nodeKey())
}
}
}
// pruneCtorGroupParams removes constructor results that are still referenced in the GroupParams of
// constructors that consume those results.
func (dg *Graph) pruneCtorGroupParams(groups map[nodeKey]*Group) {
for _, c := range dg.Ctors {
var pruned []*Group
for _, gp := range c.GroupParams {
k := gp.nodeKey()
if _, ok := groups[k]; ok {
pruned = append(pruned, gp)
}
}
c.GroupParams = pruned
}
}
// pruneGroupResults removes results of the constructor argument that are still referenced in
// the Group object that contains that result. If a group no longer exists references to that
// should should be removed.
func (dg *Graph) pruneGroupResults(c *Ctor, groups map[nodeKey]*Group) {
for _, r := range c.Results {
k := r.nodeKey()
if k.group == "" {
continue
}
g, ok := groups[k]
if ok {
g.removeResult(r)
}
}
}
// String implements fmt.Stringer for Param.
func (p *Param) String() string {
if p.Name != "" {
return fmt.Sprintf("%v[name=%v]", p.Type.String(), p.Name)
}
return p.Type.String()
}
// String implements fmt.Stringer for Result.
func (r *Result) String() string {
switch {
case r.Name != "":
return fmt.Sprintf("%v[name=%v]", r.Type.String(), r.Name)
case r.Group != "":
return fmt.Sprintf("%v[group=%v]%v", r.Type.String(), r.Group, r.GroupIndex)
default:
return r.Type.String()
}
}
// String implements fmt.Stringer for Group.
func (g *Group) String() string {
return fmt.Sprintf("[type=%v group=%v]", g.Type.String(), g.Name)
}
// Attributes composes and returns a string of the Result node's attributes.
func (r *Result) Attributes() string {
switch {
case r.Name != "":
return fmt.Sprintf(`label=<%v<BR /><FONT POINT-SIZE="10">Name: %v</FONT>>`, r.Type, r.Name)
case r.Group != "":
return fmt.Sprintf(`label=<%v<BR /><FONT POINT-SIZE="10">Group: %v</FONT>>`, r.Type, r.Group)
default:
return fmt.Sprintf(`label=<%v>`, r.Type)
}
}
// Attributes composes and returns a string of the Group node's attributes.
func (g *Group) Attributes() string {
attr := fmt.Sprintf(`shape=diamond label=<%v<BR /><FONT POINT-SIZE="10">Group: %v</FONT>>`, g.Type, g.Name)
if g.ErrorType != noError {
attr += " color=" + g.ErrorType.Color()
}
return attr
}
// Color returns the color representation of each ErrorType.
func (s ErrorType) Color() string {
switch s {
case rootCause:
return "red"
case transitiveFailure:
return "orange"
default:
return "black"
}
}
func (dg *Graph) addRootCause(r *Result) {
dg.Failed.RootCauses = append(dg.Failed.RootCauses, r)
}
func (dg *Graph) addTransitiveFailure(r *Result) {
dg.Failed.TransitiveFailures = append(dg.Failed.TransitiveFailures, r)
}

118
vendor/go.uber.org/dig/internal/graph/graph.go generated vendored Normal file
View File

@@ -0,0 +1,118 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package graph
// Graph represents a simple interface for representation
// of a directed graph.
// It is assumed that each node in the graph is uniquely
// identified with an incremental positive integer (i.e. 1, 2, 3...).
// A value of 0 for a node represents a sentinel error value.
type Graph interface {
// Order returns the total number of nodes in the graph
Order() int
// EdgesFrom returns a list of integers that each
// represents a node that has an edge from node u.
EdgesFrom(u int) []int
}
// IsAcyclic uses depth-first search to find cycles
// in a generic graph represented by Graph interface.
// If a cycle is found, it returns a list of nodes that
// are in the cyclic path, identified by their orders.
func IsAcyclic(g Graph) (bool, []int) {
// cycleStart is a node that introduces a cycle in
// the graph. Values in the range [1, g.Order()) mean
// that there exists a cycle in g.
info := newCycleInfo(g.Order())
for i := 0; i < g.Order(); i++ {
info.Reset()
cycle := isAcyclic(g, i, info, nil /* cycle path */)
if len(cycle) > 0 {
return false, cycle
}
}
return true, nil
}
// isAcyclic traverses the given graph starting from a specific node
// using depth-first search using recursion. If a cycle is detected,
// it returns the node that contains the "last" edge that introduces
// a cycle.
// For example, running isAcyclic starting from 1 on the following
// graph will return 3.
//
// 1 -> 2 -> 3 -> 1
func isAcyclic(g Graph, u int, info cycleInfo, path []int) []int {
// We've already verified that there are no cycles from this node.
if info[u].Visited {
return nil
}
info[u].Visited = true
info[u].OnStack = true
path = append(path, u)
for _, v := range g.EdgesFrom(u) {
if !info[v].Visited {
if cycle := isAcyclic(g, v, info, path); len(cycle) > 0 {
return cycle
}
} else if info[v].OnStack {
// We've found a cycle, and we have a full path back.
// Prune it down to just the cyclic nodes.
cycle := path
for i := len(cycle) - 1; i >= 0; i-- {
if cycle[i] == v {
cycle = cycle[i:]
break
}
}
// Complete the cycle by adding this node to it.
return append(cycle, v)
}
}
info[u].OnStack = false
return nil
}
// cycleNode keeps track of a single node's info for cycle detection.
type cycleNode struct {
Visited bool
OnStack bool
}
// cycleInfo contains information about each node while we're trying to find
// cycles.
type cycleInfo []cycleNode
func newCycleInfo(order int) cycleInfo {
return make(cycleInfo, order)
}
func (info cycleInfo) Reset() {
for i := range info {
info[i].OnStack = false
}
}

211
vendor/go.uber.org/dig/invoke.go generated vendored Normal file
View File

@@ -0,0 +1,211 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"go.uber.org/dig/internal/digreflect"
"go.uber.org/dig/internal/graph"
"reflect"
)
// An InvokeOption modifies the default behavior of Invoke.
type InvokeOption interface {
applyInvokeOption(*invokeOptions)
}
type invokeOptions struct {
Info *InvokeInfo
}
// InvokeInfo provides information about an Invoke.
type InvokeInfo struct {
Inputs []*Input
}
// FillInvokeInfo is an InvokeOption that writes information on the types
// accepted by the Invoke function into the specified InvokeInfo.
// For example:
//
// var info dig.InvokeInfo
// err := c.Invoke(func(string, int){}, dig.FillInvokeInfo(&info))
//
// info.Inputs[0].String() will be string.
// info.Inputs[1].String() will be int.
func FillInvokeInfo(info *InvokeInfo) InvokeOption {
return fillInvokeInfoOption{info: info}
}
type fillInvokeInfoOption struct {
info *InvokeInfo
}
func (o fillInvokeInfoOption) String() string {
return fmt.Sprintf("FillInvokeInfo(%p)", o.info)
}
func (o fillInvokeInfoOption) applyInvokeOption(opts *invokeOptions) {
opts.Info = o.info
}
// Invoke runs the given function after instantiating its dependencies.
//
// Any arguments that the function has are treated as its dependencies. The
// dependencies are instantiated in an unspecified order along with any
// dependencies that they might have.
//
// The function may return an error to indicate failure. The error will be
// returned to the caller as-is.
//
// If the [RecoverFromPanics] option was given to the container and a panic
// occurs when invoking, a [PanicError] with the panic contained will be
// returned. See [PanicError] for more info.
func (c *Container) Invoke(function interface{}, opts ...InvokeOption) error {
return c.scope.Invoke(function, opts...)
}
// Invoke runs the given function after instantiating its dependencies.
//
// Any arguments that the function has are treated as its dependencies. The
// dependencies are instantiated in an unspecified order along with any
// dependencies that they might have.
//
// The function may return an error to indicate failure. The error will be
// returned to the caller as-is.
func (s *Scope) Invoke(function interface{}, opts ...InvokeOption) (err error) {
ftype := reflect.TypeOf(function)
if ftype == nil {
return newErrInvalidInput("can't invoke an untyped nil", nil)
}
if ftype.Kind() != reflect.Func {
return newErrInvalidInput(
fmt.Sprintf("can't invoke non-function %v (type %v)", function, ftype), nil)
}
pl, err := newParamList(ftype, s)
if err != nil {
return err
}
if err := shallowCheckDependencies(s, pl); err != nil {
return errMissingDependencies{
Func: digreflect.InspectFunc(function),
Reason: err,
}
}
if !s.isVerifiedAcyclic {
if ok, cycle := graph.IsAcyclic(s.gh); !ok {
return newErrInvalidInput("cycle detected in dependency graph", s.cycleDetectedError(cycle))
}
s.isVerifiedAcyclic = true
}
args, err := pl.BuildList(s)
if err != nil {
return errArgumentsFailed{
Func: digreflect.InspectFunc(function),
Reason: err,
}
}
if s.recoverFromPanics {
defer func() {
if p := recover(); p != nil {
err = PanicError{
fn: digreflect.InspectFunc(function),
Panic: p,
}
}
}()
}
var options invokeOptions
for _, o := range opts {
o.applyInvokeOption(&options)
}
// Record info for the invoke if requested
if info := options.Info; info != nil {
params := pl.DotParam()
info.Inputs = make([]*Input, len(params))
for i, p := range params {
info.Inputs[i] = &Input{
t: p.Type,
optional: p.Optional,
name: p.Name,
group: p.Group,
}
}
}
returned := s.invokerFn(reflect.ValueOf(function), args)
if len(returned) == 0 {
return nil
}
if last := returned[len(returned)-1]; isError(last.Type()) {
if err, _ := last.Interface().(error); err != nil {
return err
}
}
return nil
}
// Checks that all direct dependencies of the provided parameters are present in
// the container. Returns an error if not.
func shallowCheckDependencies(c containerStore, pl paramList) error {
var err errMissingTypes
missingDeps := findMissingDependencies(c, pl.Params...)
for _, dep := range missingDeps {
err = append(err, newErrMissingTypes(c, key{name: dep.Name, t: dep.Type})...)
}
if len(err) > 0 {
return err
}
return nil
}
func findMissingDependencies(c containerStore, params ...param) []paramSingle {
var missingDeps []paramSingle
for _, param := range params {
switch p := param.(type) {
case paramSingle:
allProviders := c.getAllValueProviders(p.Name, p.Type)
_, hasDecoratedValue := c.getDecoratedValue(p.Name, p.Type)
// This means that there is no provider that provides this value,
// and it is NOT being decorated and is NOT optional.
// In the case that there is no providers but there is a decorated value
// of this type, it can be provided safely so we can safely skip this.
if len(allProviders) == 0 && !hasDecoratedValue && !p.Optional {
missingDeps = append(missingDeps, p)
}
case paramObject:
for _, f := range p.Fields {
missingDeps = append(missingDeps, findMissingDependencies(c, f.Param)...)
}
}
}
return missingDeps
}

668
vendor/go.uber.org/dig/param.go generated vendored Normal file
View File

@@ -0,0 +1,668 @@
// Copyright (c) 2019-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"reflect"
"strconv"
"strings"
"go.uber.org/dig/internal/digerror"
"go.uber.org/dig/internal/dot"
)
// The param interface represents a dependency for a constructor.
//
// The following implementations exist:
//
// paramList All arguments of the constructor.
// paramSingle An explicitly requested type.
// paramObject dig.In struct where each field in the struct can be another
// param.
// paramGroupedSlice
// A slice consuming a value group. This will receive all
// values produced with a `group:".."` tag with the same name
// as a slice.
type param interface {
fmt.Stringer
// Build this dependency and any of its dependencies from the provided
// Container.
//
// This MAY panic if the param does not produce a single value.
Build(store containerStore) (reflect.Value, error)
// DotParam returns a slice of dot.Param(s).
DotParam() []*dot.Param
}
var (
_ param = paramSingle{}
_ param = paramObject{}
_ param = paramList{}
_ param = paramGroupedSlice{}
)
// newParam builds a param from the given type. If the provided type is a
// dig.In struct, an paramObject will be returned.
func newParam(t reflect.Type, c containerStore) (param, error) {
switch {
case IsOut(t) || (t.Kind() == reflect.Ptr && IsOut(t.Elem())) || embedsType(t, _outPtrType):
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot depend on result objects: %v embeds a dig.Out", t), nil)
case IsIn(t):
return newParamObject(t, c)
case embedsType(t, _inPtrType):
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot build a parameter object by embedding *dig.In, embed dig.In instead: %v embeds *dig.In", t), nil)
case t.Kind() == reflect.Ptr && IsIn(t.Elem()):
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot depend on a pointer to a parameter object, use a value instead: %v is a pointer to a struct that embeds dig.In", t), nil)
default:
return paramSingle{Type: t}, nil
}
}
// paramList holds all arguments of the constructor as params.
//
// NOTE: Build() MUST NOT be called on paramList. Instead, BuildList
// must be called.
type paramList struct {
ctype reflect.Type // type of the constructor
Params []param
}
func (pl paramList) DotParam() []*dot.Param {
var types []*dot.Param
for _, param := range pl.Params {
types = append(types, param.DotParam()...)
}
return types
}
func (pl paramList) String() string {
args := make([]string, len(pl.Params))
for i, p := range pl.Params {
args[i] = p.String()
}
return fmt.Sprint(args)
}
// newParamList builds a paramList from the provided constructor type.
//
// Variadic arguments of a constructor are ignored and not included as
// dependencies.
func newParamList(ctype reflect.Type, c containerStore) (paramList, error) {
numArgs := ctype.NumIn()
if ctype.IsVariadic() {
// NOTE: If the function is variadic, we skip the last argument
// because we're not filling variadic arguments yet. See #120.
numArgs--
}
pl := paramList{
ctype: ctype,
Params: make([]param, 0, numArgs),
}
for i := 0; i < numArgs; i++ {
p, err := newParam(ctype.In(i), c)
if err != nil {
return pl, newErrInvalidInput(fmt.Sprintf("bad argument %d", i+1), err)
}
pl.Params = append(pl.Params, p)
}
return pl, nil
}
func (pl paramList) Build(containerStore) (reflect.Value, error) {
digerror.BugPanicf("paramList.Build() must never be called")
panic("") // Unreachable, as BugPanicf above will panic.
}
// BuildList returns an ordered list of values which may be passed directly
// to the underlying constructor.
func (pl paramList) BuildList(c containerStore) ([]reflect.Value, error) {
args := make([]reflect.Value, len(pl.Params))
for i, p := range pl.Params {
var err error
args[i], err = p.Build(c)
if err != nil {
return nil, err
}
}
return args, nil
}
// paramSingle is an explicitly requested type, optionally with a name.
//
// This object must be present in the graph as-is unless it's specified as
// optional.
type paramSingle struct {
Name string
Optional bool
Type reflect.Type
}
func (ps paramSingle) DotParam() []*dot.Param {
return []*dot.Param{
{
Node: &dot.Node{
Type: ps.Type,
Name: ps.Name,
},
Optional: ps.Optional,
},
}
}
func (ps paramSingle) String() string {
// tally.Scope[optional] means optional
// tally.Scope[optional, name="foo"] means named optional
var opts []string
if ps.Optional {
opts = append(opts, "optional")
}
if ps.Name != "" {
opts = append(opts, fmt.Sprintf("name=%q", ps.Name))
}
if len(opts) == 0 {
return fmt.Sprint(ps.Type)
}
return fmt.Sprintf("%v[%v]", ps.Type, strings.Join(opts, ", "))
}
// search the given container and its ancestors for a decorated value.
func (ps paramSingle) getDecoratedValue(c containerStore) (reflect.Value, bool) {
for _, c := range c.storesToRoot() {
if v, ok := c.getDecoratedValue(ps.Name, ps.Type); ok {
return v, ok
}
}
return _noValue, false
}
// builds the parameter using decorators in all scopes that affect the
// current scope, if there are any. If there are multiple Scopes that decorates
// this parameter, the closest one to the Scope that invoked this will be used.
// If there are no decorators associated with this parameter, _noValue is returned.
func (ps paramSingle) buildWithDecorators(c containerStore) (v reflect.Value, found bool, err error) {
var (
d decorator
decoratingScope containerStore
)
stores := c.storesToRoot()
for _, s := range stores {
if d, found = s.getValueDecorator(ps.Name, ps.Type); !found {
continue
}
if d.State() == decoratorOnStack {
// This decorator is already being run.
// Avoid a cycle and look further.
d = nil
continue
}
decoratingScope = s
break
}
if !found || d == nil {
return _noValue, false, nil
}
if err = d.Call(decoratingScope); err != nil {
v, err = _noValue, errParamSingleFailed{
CtorID: 1,
Key: key{t: ps.Type, name: ps.Name},
Reason: err,
}
return v, found, err
}
v, _ = decoratingScope.getDecoratedValue(ps.Name, ps.Type)
return
}
func (ps paramSingle) Build(c containerStore) (reflect.Value, error) {
v, found, err := ps.buildWithDecorators(c)
if found {
return v, err
}
// Check whether the value is a decorated value first.
if v, ok := ps.getDecoratedValue(c); ok {
return v, nil
}
// Starting at the given container and working our way up its parents,
// find one that provides this dependency.
//
// Once found, we'll use that container for the rest of the invocation.
// Dependencies of this type will begin searching at that container,
// rather than starting at base.
var providers []provider
var providingContainer containerStore
for _, container := range c.storesToRoot() {
// first check if the scope already has cached a value for the type.
if v, ok := container.getValue(ps.Name, ps.Type); ok {
return v, nil
}
providers = container.getValueProviders(ps.Name, ps.Type)
if len(providers) > 0 {
providingContainer = container
break
}
}
if len(providers) == 0 {
if ps.Optional {
return reflect.Zero(ps.Type), nil
}
return _noValue, newErrMissingTypes(c, key{name: ps.Name, t: ps.Type})
}
for _, n := range providers {
err := n.Call(n.OrigScope())
if err == nil {
continue
}
// If we're missing dependencies but the parameter itself is optional,
// we can just move on.
if _, ok := err.(errMissingDependencies); ok && ps.Optional {
return reflect.Zero(ps.Type), nil
}
return _noValue, errParamSingleFailed{
CtorID: n.ID(),
Key: key{t: ps.Type, name: ps.Name},
Reason: err,
}
}
// If we get here, it's impossible for the value to be absent from the
// container.
v, _ = providingContainer.getValue(ps.Name, ps.Type)
return v, nil
}
// paramObject is a dig.In struct where each field is another param.
//
// This object is not expected in the graph as-is.
type paramObject struct {
Type reflect.Type
Fields []paramObjectField
FieldOrders []int
}
func (po paramObject) DotParam() []*dot.Param {
var types []*dot.Param
for _, field := range po.Fields {
types = append(types, field.DotParam()...)
}
return types
}
func (po paramObject) String() string {
fields := make([]string, len(po.Fields))
for i, f := range po.Fields {
fields[i] = f.Param.String()
}
return strings.Join(fields, " ")
}
// getParamOrder returns the order(s) of a parameter type.
func getParamOrder(gh *graphHolder, param param) []int {
var orders []int
switch p := param.(type) {
case paramSingle:
providers := gh.s.getAllValueProviders(p.Name, p.Type)
for _, provider := range providers {
orders = append(orders, provider.Order(gh.s))
}
case paramGroupedSlice:
// value group parameters have nodes of their own.
// We can directly return that here.
orders = append(orders, p.orders[gh.s])
case paramObject:
for _, pf := range p.Fields {
orders = append(orders, getParamOrder(gh, pf.Param)...)
}
}
return orders
}
// newParamObject builds an paramObject from the provided type. The type MUST
// be a dig.In struct.
func newParamObject(t reflect.Type, c containerStore) (paramObject, error) {
po := paramObject{Type: t}
// Check if the In type supports ignoring unexported fields.
var ignoreUnexported bool
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.Type == _inType {
var err error
ignoreUnexported, err = isIgnoreUnexportedSet(f)
if err != nil {
return po, err
}
break
}
}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.Type == _inType {
// Skip over the dig.In embed.
continue
}
if f.PkgPath != "" && ignoreUnexported {
// Skip over an unexported field if it is allowed.
continue
}
pof, err := newParamObjectField(i, f, c)
if err != nil {
return po, newErrInvalidInput(
fmt.Sprintf("bad field %q of %v", f.Name, t), err)
}
po.Fields = append(po.Fields, pof)
}
return po, nil
}
func (po paramObject) Build(c containerStore) (reflect.Value, error) {
dest := reflect.New(po.Type).Elem()
// We have to build soft groups after all other fields, to avoid cases
// when a field calls a provider for a soft value group, but the value is
// not provided to it because the value group is declared before the field
var softGroupsQueue []paramObjectField
var fields []paramObjectField
for _, f := range po.Fields {
if p, ok := f.Param.(paramGroupedSlice); ok && p.Soft {
softGroupsQueue = append(softGroupsQueue, f)
continue
}
fields = append(fields, f)
}
fields = append(fields, softGroupsQueue...)
for _, f := range fields {
v, err := f.Build(c)
if err != nil {
return dest, err
}
dest.Field(f.FieldIndex).Set(v)
}
return dest, nil
}
// paramObjectField is a single field of a dig.In struct.
type paramObjectField struct {
// Name of the field in the struct.
FieldName string
// Index of this field in the target struct.
//
// We need to track this separately because not all fields of the
// struct map to params.
FieldIndex int
// The dependency requested by this field.
Param param
}
func (pof paramObjectField) DotParam() []*dot.Param {
return pof.Param.DotParam()
}
func newParamObjectField(idx int, f reflect.StructField, c containerStore) (paramObjectField, error) {
pof := paramObjectField{
FieldName: f.Name,
FieldIndex: idx,
}
var p param
switch {
case f.PkgPath != "":
return pof, newErrInvalidInput(
fmt.Sprintf("unexported fields not allowed in dig.In, did you mean to export %q (%v)?", f.Name, f.Type), nil)
case f.Tag.Get(_groupTag) != "":
var err error
p, err = newParamGroupedSlice(f, c)
if err != nil {
return pof, err
}
default:
var err error
p, err = newParam(f.Type, c)
if err != nil {
return pof, err
}
}
if ps, ok := p.(paramSingle); ok {
ps.Name = f.Tag.Get(_nameTag)
var err error
ps.Optional, err = isFieldOptional(f)
if err != nil {
return pof, err
}
p = ps
}
pof.Param = p
return pof, nil
}
func (pof paramObjectField) Build(c containerStore) (reflect.Value, error) {
v, err := pof.Param.Build(c)
if err != nil {
return v, err
}
return v, nil
}
// paramGroupedSlice is a param which produces a slice of values with the same
// group name.
type paramGroupedSlice struct {
// Name of the group as specified in the `group:".."` tag.
Group string
// Type of the slice.
Type reflect.Type
// Soft is used to denote a soft dependency between this param and its
// constructors, if it's true its constructors are only called if they
// provide another value requested in the graph
Soft bool
orders map[*Scope]int
}
func (pt paramGroupedSlice) String() string {
// io.Reader[group="foo"] refers to a group of io.Readers called 'foo'
return fmt.Sprintf("%v[group=%q]", pt.Type.Elem(), pt.Group)
}
func (pt paramGroupedSlice) DotParam() []*dot.Param {
return []*dot.Param{
{
Node: &dot.Node{
Type: pt.Type,
Group: pt.Group,
},
},
}
}
// newParamGroupedSlice builds a paramGroupedSlice from the provided type with
// the given name.
//
// The type MUST be a slice type.
func newParamGroupedSlice(f reflect.StructField, c containerStore) (paramGroupedSlice, error) {
g, err := parseGroupString(f.Tag.Get(_groupTag))
if err != nil {
return paramGroupedSlice{}, err
}
pg := paramGroupedSlice{
Group: g.Name,
Type: f.Type,
orders: make(map[*Scope]int),
Soft: g.Soft,
}
name := f.Tag.Get(_nameTag)
optional, _ := isFieldOptional(f)
switch {
case f.Type.Kind() != reflect.Slice:
return pg, newErrInvalidInput(
fmt.Sprintf("value groups may be consumed as slices only: field %q (%v) is not a slice", f.Name, f.Type), nil)
case g.Flatten:
return pg, newErrInvalidInput(
fmt.Sprintf("cannot use flatten in parameter value groups: field %q (%v) specifies flatten", f.Name, f.Type), nil)
case name != "":
return pg, newErrInvalidInput(
fmt.Sprintf("cannot use named values with value groups: name:%q requested with group:%q", name, pg.Group), nil)
case optional:
return pg, newErrInvalidInput("value groups cannot be optional", nil)
}
c.newGraphNode(&pg, pg.orders)
return pg, nil
}
// retrieves any decorated values that may be committed in this scope, or
// any of the parent Scopes. In the case where there are multiple scopes that
// are decorating the same type, the closest scope in effect will be replacing
// any decorated value groups provided in further scopes.
func (pt paramGroupedSlice) getDecoratedValues(c containerStore) (reflect.Value, bool) {
for _, c := range c.storesToRoot() {
if items, ok := c.getDecoratedValueGroup(pt.Group, pt.Type); ok {
return items, true
}
}
return _noValue, false
}
// search the given container and its parents for matching group decorators
// and call them to commit values. If any decorators return an error,
// that error is returned immediately. If all decorators succeeds, nil is returned.
// The order in which the decorators are invoked is from the top level scope to
// the current scope, to account for decorators that decorate values that were
// already decorated.
func (pt paramGroupedSlice) callGroupDecorators(c containerStore) error {
stores := c.storesToRoot()
for i := len(stores) - 1; i >= 0; i-- {
c := stores[i]
if d, found := c.getGroupDecorator(pt.Group, pt.Type.Elem()); found {
if d.State() == decoratorOnStack {
// This decorator is already being run. Avoid cycle
// and look further.
continue
}
if err := d.Call(c); err != nil {
return errParamGroupFailed{
CtorID: d.ID(),
Key: key{group: pt.Group, t: pt.Type.Elem()},
Reason: err,
}
}
}
}
return nil
}
// search the given container and its parent for matching group providers and
// call them to commit values. If an error is encountered, return the number
// of providers called and a non-nil error from the first provided.
func (pt paramGroupedSlice) callGroupProviders(c containerStore) (int, error) {
itemCount := 0
for _, c := range c.storesToRoot() {
providers := c.getGroupProviders(pt.Group, pt.Type.Elem())
itemCount += len(providers)
for _, n := range providers {
if err := n.Call(n.OrigScope()); err != nil {
return 0, errParamGroupFailed{
CtorID: n.ID(),
Key: key{group: pt.Group, t: pt.Type.Elem()},
Reason: err,
}
}
}
}
return itemCount, nil
}
func (pt paramGroupedSlice) Build(c containerStore) (reflect.Value, error) {
// do not call this if we are already inside a decorator since
// it will result in an infinite recursion. (i.e. decorate -> params.BuildList() -> Decorate -> params.BuildList...)
// this is safe since a value can be decorated at most once in a given scope.
if err := pt.callGroupDecorators(c); err != nil {
return _noValue, err
}
// Check if we have decorated values
if decoratedItems, ok := pt.getDecoratedValues(c); ok {
return decoratedItems, nil
}
// If we do not have any decorated values and the group isn't soft,
// find the providers and call them.
itemCount := 0
if !pt.Soft {
var err error
itemCount, err = pt.callGroupProviders(c)
if err != nil {
return _noValue, err
}
}
stores := c.storesToRoot()
result := reflect.MakeSlice(pt.Type, 0, itemCount)
for _, c := range stores {
result = reflect.Append(result, c.getValueGroup(pt.Group, pt.Type.Elem())...)
}
return result, nil
}
// Checks if ignoring unexported files in an In struct is allowed.
// The struct field MUST be an _inType.
func isIgnoreUnexportedSet(f reflect.StructField) (bool, error) {
tag := f.Tag.Get(_ignoreUnexportedTag)
if tag == "" {
return false, nil
}
allowed, err := strconv.ParseBool(tag)
if err != nil {
err = newErrInvalidInput(
fmt.Sprintf("invalid value %q for %q tag on field %v", tag, _ignoreUnexportedTag, f.Name), err)
}
return allowed, err
}

665
vendor/go.uber.org/dig/provide.go generated vendored Normal file
View File

@@ -0,0 +1,665 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"bytes"
"fmt"
"reflect"
"strings"
"go.uber.org/dig/internal/digreflect"
"go.uber.org/dig/internal/dot"
"go.uber.org/dig/internal/graph"
)
// A ProvideOption modifies the default behavior of Provide.
type ProvideOption interface {
applyProvideOption(*provideOptions)
}
type provideOptions struct {
Name string
Group string
Info *ProvideInfo
As []interface{}
Location *digreflect.Func
Exported bool
Callback Callback
}
func (o *provideOptions) Validate() error {
if len(o.Group) > 0 {
if len(o.Name) > 0 {
return newErrInvalidInput(
fmt.Sprintf("cannot use named values with value groups: name:%q provided with group:%q", o.Name, o.Group), nil)
}
}
// Names must be representable inside a backquoted string. The only
// limitation for raw string literals as per
// https://golang.org/ref/spec#raw_string_lit is that they cannot contain
// backquotes.
if strings.ContainsRune(o.Name, '`') {
return newErrInvalidInput(
fmt.Sprintf("invalid dig.Name(%q): names cannot contain backquotes", o.Name), nil)
}
if strings.ContainsRune(o.Group, '`') {
return newErrInvalidInput(
fmt.Sprintf("invalid dig.Group(%q): group names cannot contain backquotes", o.Group), nil)
}
for _, i := range o.As {
t := reflect.TypeOf(i)
if t == nil {
return newErrInvalidInput("invalid dig.As(nil): argument must be a pointer to an interface", nil)
}
if t.Kind() != reflect.Ptr {
return newErrInvalidInput(
fmt.Sprintf("invalid dig.As(%v): argument must be a pointer to an interface", t), nil)
}
pointingTo := t.Elem()
if pointingTo.Kind() != reflect.Interface {
return newErrInvalidInput(
fmt.Sprintf("invalid dig.As(*%v): argument must be a pointer to an interface", pointingTo), nil)
}
}
return nil
}
// Name is a ProvideOption that specifies that all values produced by a
// constructor should have the given name. See also the package documentation
// about Named Values.
//
// Given,
//
// func NewReadOnlyConnection(...) (*Connection, error)
// func NewReadWriteConnection(...) (*Connection, error)
//
// The following will provide two connections to the container: one under the
// name "ro" and the other under the name "rw".
//
// c.Provide(NewReadOnlyConnection, dig.Name("ro"))
// c.Provide(NewReadWriteConnection, dig.Name("rw"))
//
// This option cannot be provided for constructors which produce result
// objects.
func Name(name string) ProvideOption {
return provideNameOption(name)
}
type provideNameOption string
func (o provideNameOption) String() string {
return fmt.Sprintf("Name(%q)", string(o))
}
func (o provideNameOption) applyProvideOption(opt *provideOptions) {
opt.Name = string(o)
}
// Group is a ProvideOption that specifies that all values produced by a
// constructor should be added to the specified group. See also the package
// documentation about Value Groups.
//
// This option cannot be provided for constructors which produce result
// objects.
func Group(group string) ProvideOption {
return provideGroupOption(group)
}
type provideGroupOption string
func (o provideGroupOption) String() string {
return fmt.Sprintf("Group(%q)", string(o))
}
func (o provideGroupOption) applyProvideOption(opt *provideOptions) {
opt.Group = string(o)
}
// ID is a unique integer representing the constructor node in the dependency graph.
type ID int
// ProvideInfo provides information about the constructor's inputs and outputs
// types as strings, as well as the ID of the constructor supplied to the Container.
// It contains ID for the constructor, as well as slices of Input and Output types,
// which are Stringers that report the types of the parameters and results respectively.
type ProvideInfo struct {
ID ID
Inputs []*Input
Outputs []*Output
}
// Input contains information on an input parameter of a function.
type Input struct {
t reflect.Type
optional bool
name, group string
}
func (i *Input) String() string {
toks := make([]string, 0, 3)
t := i.t.String()
if i.optional {
toks = append(toks, "optional")
}
if i.name != "" {
toks = append(toks, fmt.Sprintf("name = %q", i.name))
}
if i.group != "" {
toks = append(toks, fmt.Sprintf("group = %q", i.group))
}
if len(toks) == 0 {
return t
}
return fmt.Sprintf("%v[%v]", t, strings.Join(toks, ", "))
}
// Output contains information on an output produced by a function.
type Output struct {
t reflect.Type
name, group string
}
func (o *Output) String() string {
toks := make([]string, 0, 2)
t := o.t.String()
if o.name != "" {
toks = append(toks, fmt.Sprintf("name = %q", o.name))
}
if o.group != "" {
toks = append(toks, fmt.Sprintf("group = %q", o.group))
}
if len(toks) == 0 {
return t
}
return fmt.Sprintf("%v[%v]", t, strings.Join(toks, ", "))
}
// FillProvideInfo is a ProvideOption that writes info on what Dig was able to get
// out of the provided constructor into the provided ProvideInfo.
func FillProvideInfo(info *ProvideInfo) ProvideOption {
return fillProvideInfoOption{info: info}
}
type fillProvideInfoOption struct{ info *ProvideInfo }
func (o fillProvideInfoOption) String() string {
return fmt.Sprintf("FillProvideInfo(%p)", o.info)
}
func (o fillProvideInfoOption) applyProvideOption(opts *provideOptions) {
opts.Info = o.info
}
// As is a ProvideOption that specifies that the value produced by the
// constructor implements one or more other interfaces and is provided
// to the container as those interfaces.
//
// As expects one or more pointers to the implemented interfaces. Values
// produced by constructors will be then available in the container as
// implementations of all of those interfaces, but not as the value itself.
//
// For example, the following will make io.Reader and io.Writer available
// in the container, but not buffer.
//
// c.Provide(newBuffer, dig.As(new(io.Reader), new(io.Writer)))
//
// That is, the above is equivalent to the following.
//
// c.Provide(func(...) (io.Reader, io.Writer) {
// b := newBuffer(...)
// return b, b
// })
//
// If used with dig.Name, the type produced by the constructor and the types
// specified with dig.As will all use the same name. For example,
//
// c.Provide(newFile, dig.As(new(io.Reader)), dig.Name("temp"))
//
// The above is equivalent to the following.
//
// type Result struct {
// dig.Out
//
// Reader io.Reader `name:"temp"`
// }
//
// c.Provide(func(...) Result {
// f := newFile(...)
// return Result{
// Reader: f,
// }
// })
//
// This option cannot be provided for constructors which produce result
// objects.
func As(i ...interface{}) ProvideOption {
return provideAsOption(i)
}
type provideAsOption []interface{}
func (o provideAsOption) String() string {
buf := bytes.NewBufferString("As(")
for i, iface := range o {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(reflect.TypeOf(iface).Elem().String())
}
buf.WriteString(")")
return buf.String()
}
func (o provideAsOption) applyProvideOption(opts *provideOptions) {
opts.As = append(opts.As, o...)
}
// LocationForPC is a ProvideOption which specifies an alternate function program
// counter address to be used for debug information. The package, name, file and
// line number of this alternate function address will be used in error messages
// and DOT graphs. This option is intended to be used with functions created
// with the reflect.MakeFunc method whose error messages are otherwise hard to
// understand
func LocationForPC(pc uintptr) ProvideOption {
return provideLocationOption{
loc: digreflect.InspectFuncPC(pc),
}
}
type provideLocationOption struct{ loc *digreflect.Func }
func (o provideLocationOption) String() string {
return fmt.Sprintf("LocationForPC(%v)", o.loc)
}
func (o provideLocationOption) applyProvideOption(opts *provideOptions) {
opts.Location = o.loc
}
// Export is a ProvideOption which specifies that the provided function should
// be made available to all Scopes available in the application, regardless
// of which Scope it was provided from. By default, it is false.
//
// For example,
//
// c := New()
// s1 := c.Scope("child 1")
// s2:= c.Scope("child 2")
// s1.Provide(func() *bytes.Buffer { ... })
//
// does not allow the constructor returning *bytes.Buffer to be made available to
// the root Container c or its sibling Scope s2.
//
// With Export, you can make this constructor available to all the Scopes:
//
// s1.Provide(func() *bytes.Buffer { ... }, Export(true))
func Export(export bool) ProvideOption {
return provideExportOption{exported: export}
}
type provideExportOption struct{ exported bool }
func (o provideExportOption) String() string {
return fmt.Sprintf("Export(%v)", o.exported)
}
func (o provideExportOption) applyProvideOption(opts *provideOptions) {
opts.Exported = o.exported
}
// provider encapsulates a user-provided constructor.
type provider interface {
// ID is a unique numerical identifier for this provider.
ID() dot.CtorID
// Order reports the order of this provider in the graphHolder.
// This value is usually returned by the graphHolder.NewNode method.
Order(*Scope) int
// Location returns where this constructor was defined.
Location() *digreflect.Func
// ParamList returns information about the direct dependencies of this
// constructor.
ParamList() paramList
// ResultList returns information about the values produced by this
// constructor.
ResultList() resultList
// Calls the underlying constructor, reading values from the
// containerStore as needed.
//
// The values produced by this provider should be submitted into the
// containerStore.
Call(containerStore) error
CType() reflect.Type
OrigScope() *Scope
}
// Provide teaches the container how to build values of one or more types and
// expresses their dependencies.
//
// The first argument of Provide is a function that accepts zero or more
// parameters and returns one or more results. The function may optionally
// return an error to indicate that it failed to build the value. This
// function will be treated as the constructor for all the types it returns.
// This function will be called AT MOST ONCE when a type produced by it, or a
// type that consumes this function's output, is requested via Invoke. If the
// same types are requested multiple times, the previously produced value will
// be reused.
//
// Provide accepts argument types or dig.In structs as dependencies, and
// separate return values or dig.Out structs for results.
func (c *Container) Provide(constructor interface{}, opts ...ProvideOption) error {
return c.scope.Provide(constructor, opts...)
}
// Provide teaches the Scope how to build values of one or more types and
// expresses their dependencies.
//
// The first argument of Provide is a function that accepts zero or more
// parameters and returns one or more results. The function may optionally
// return an error to indicate that it failed to build the value. This
// function will be treated as the constructor for all the types it returns.
// This function will be called AT MOST ONCE when a type produced by it, or a
// type that consumes this function's output, is requested via Invoke. If the
// same types are requested multiple times, the previously produced value will
// be reused.
//
// Provide accepts argument types or dig.In structs as dependencies, and
// separate return values or dig.Out structs for results.
//
// When a constructor is Provided to a Scope, it will propagate this to any
// Scopes that are descendents, but not ancestors of this Scope.
// To provide a constructor to all the Scopes available, provide it to
// Container, which is the root Scope.
func (s *Scope) Provide(constructor interface{}, opts ...ProvideOption) error {
ctype := reflect.TypeOf(constructor)
if ctype == nil {
return newErrInvalidInput("can't provide an untyped nil", nil)
}
if ctype.Kind() != reflect.Func {
return newErrInvalidInput(
fmt.Sprintf("must provide constructor function, got %v (type %v)", constructor, ctype), nil)
}
var options provideOptions
for _, o := range opts {
o.applyProvideOption(&options)
}
if err := options.Validate(); err != nil {
return err
}
if err := s.provide(constructor, options); err != nil {
var errFunc *digreflect.Func
if options.Location == nil {
errFunc = digreflect.InspectFunc(constructor)
} else {
errFunc = options.Location
}
return errProvide{
Func: errFunc,
Reason: err,
}
}
return nil
}
func (s *Scope) provide(ctor interface{}, opts provideOptions) (err error) {
// If Export option is provided to the constructor, this should be injected to the
// root-level Scope (Container) to allow it to propagate to all other Scopes.
origScope := s
if opts.Exported {
s = s.rootScope()
}
// For all scopes affected by this change,
// take a snapshot of the current graph state before
// we start making changes to it as we may need to
// undo them upon encountering errors.
allScopes := s.appendSubscopes(nil)
for _, s := range allScopes {
s := s
s.gh.Snapshot()
defer func() {
if err != nil {
s.gh.Rollback()
}
}()
}
n, err := newConstructorNode(
ctor,
s,
origScope,
constructorOptions{
ResultName: opts.Name,
ResultGroup: opts.Group,
ResultAs: opts.As,
Location: opts.Location,
Callback: opts.Callback,
},
)
if err != nil {
return err
}
keys, err := s.findAndValidateResults(n.ResultList())
if err != nil {
return err
}
ctype := reflect.TypeOf(ctor)
if len(keys) == 0 {
return newErrInvalidInput(
fmt.Sprintf("%v must provide at least one non-error type", ctype), nil)
}
oldProviders := make(map[key][]*constructorNode)
for k := range keys {
// Cache old providers before running cycle detection.
oldProviders[k] = s.providers[k]
s.providers[k] = append(s.providers[k], n)
}
for _, s := range allScopes {
s.isVerifiedAcyclic = false
if s.deferAcyclicVerification {
continue
}
if ok, cycle := graph.IsAcyclic(s.gh); !ok {
// When a cycle is detected, recover the old providers to reset
// the providers map back to what it was before this node was
// introduced.
for k, ops := range oldProviders {
s.providers[k] = ops
}
return newErrInvalidInput("this function introduces a cycle", s.cycleDetectedError(cycle))
}
s.isVerifiedAcyclic = true
}
s.nodes = append(s.nodes, n)
// Record introspection info for caller if Info option is specified
if info := opts.Info; info != nil {
params := n.ParamList().DotParam()
results := n.ResultList().DotResult()
info.ID = (ID)(n.id)
info.Inputs = make([]*Input, len(params))
info.Outputs = make([]*Output, len(results))
for i, param := range params {
info.Inputs[i] = &Input{
t: param.Type,
optional: param.Optional,
name: param.Name,
group: param.Group,
}
}
for i, res := range results {
info.Outputs[i] = &Output{
t: res.Type,
name: res.Name,
group: res.Group,
}
}
}
return nil
}
// Builds a collection of all result types produced by this constructor.
func (s *Scope) findAndValidateResults(rl resultList) (map[key]struct{}, error) {
var err error
keyPaths := make(map[key]string)
walkResult(rl, connectionVisitor{
s: s,
err: &err,
keyPaths: keyPaths,
})
if err != nil {
return nil, err
}
keys := make(map[key]struct{}, len(keyPaths))
for k := range keyPaths {
keys[k] = struct{}{}
}
return keys, nil
}
// Visits the results of a node and compiles a collection of all the keys
// produced by that node.
type connectionVisitor struct {
s *Scope
// If this points to a non-nil value, we've already encountered an error
// and should stop traversing.
err *error
// Map of keys provided to path that provided this. The path is a string
// documenting which positional return value or dig.Out attribute is
// providing this particular key.
//
// For example, "[0].Foo" indicates that the value was provided by the Foo
// attribute of the dig.Out returned as the first result of the
// constructor.
keyPaths map[key]string
// We track the path to the current result here. For example, this will
// be, ["[1]", "Foo", "Bar"] when we're visiting Bar in,
//
// func() (io.Writer, struct {
// dig.Out
//
// Foo struct {
// dig.Out
//
// Bar io.Reader
// }
// })
currentResultPath []string
}
func (cv connectionVisitor) AnnotateWithField(f resultObjectField) resultVisitor {
cv.currentResultPath = append(cv.currentResultPath, f.FieldName)
return cv
}
func (cv connectionVisitor) AnnotateWithPosition(i int) resultVisitor {
cv.currentResultPath = append(cv.currentResultPath, fmt.Sprintf("[%d]", i))
return cv
}
func (cv connectionVisitor) Visit(res result) resultVisitor {
// Already failed. Stop looking.
if *cv.err != nil {
return nil
}
path := strings.Join(cv.currentResultPath, ".")
switch r := res.(type) {
case resultSingle:
k := key{name: r.Name, t: r.Type}
if err := cv.checkKey(k, path); err != nil {
*cv.err = err
return nil
}
for _, asType := range r.As {
k := key{name: r.Name, t: asType}
if err := cv.checkKey(k, path); err != nil {
*cv.err = err
return nil
}
}
case resultGrouped:
// we don't really care about the path for this since conflicts are
// okay for group results. We'll track it for the sake of having a
// value there.
k := key{group: r.Group, t: r.Type}
cv.keyPaths[k] = path
for _, asType := range r.As {
k := key{group: r.Group, t: asType}
cv.keyPaths[k] = path
}
}
return cv
}
func (cv connectionVisitor) checkKey(k key, path string) error {
defer func() { cv.keyPaths[k] = path }()
if conflict, ok := cv.keyPaths[k]; ok {
return newErrInvalidInput(fmt.Sprintf("cannot provide %v from %v", k, path),
newErrInvalidInput(fmt.Sprintf("already provided by %v", conflict), nil))
}
if ps := cv.s.providers[k]; len(ps) > 0 {
cons := make([]string, len(ps))
for i, p := range ps {
cons[i] = fmt.Sprint(p.Location())
}
return newErrInvalidInput(fmt.Sprintf("cannot provide %v from %v", k, path),
newErrInvalidInput(fmt.Sprintf("already provided by %v", strings.Join(cons, "; ")), nil))
}
return nil
}

535
vendor/go.uber.org/dig/result.go generated vendored Normal file
View File

@@ -0,0 +1,535 @@
// Copyright (c) 2019-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"fmt"
"reflect"
"go.uber.org/dig/internal/digerror"
"go.uber.org/dig/internal/dot"
)
// The result interface represents a result produced by a constructor.
//
// The following implementations exist:
// resultList All values returned by the constructor.
// resultSingle A single value produced by a constructor.
// resultObject dig.Out struct where each field in the struct can be
// another result.
// resultGrouped A value produced by a constructor that is part of a value
// group.
type result interface {
// Extracts the values for this result from the provided value and
// stores them into the provided containerWriter.
//
// This MAY panic if the result does not consume a single value.
Extract(containerWriter, bool, reflect.Value)
// DotResult returns a slice of dot.Result(s).
DotResult() []*dot.Result
}
var (
_ result = resultSingle{}
_ result = resultObject{}
_ result = resultList{}
_ result = resultGrouped{}
)
type resultOptions struct {
// If set, this is the name of the associated result value.
//
// For Result Objects, name:".." tags on fields override this.
Name string
Group string
As []interface{}
}
// newResult builds a result from the given type.
func newResult(t reflect.Type, opts resultOptions) (result, error) {
switch {
case IsIn(t) || (t.Kind() == reflect.Ptr && IsIn(t.Elem())) || embedsType(t, _inPtrType):
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot provide parameter objects: %v embeds a dig.In", t), nil)
case isError(t):
return nil, newErrInvalidInput("cannot return an error here, return it from the constructor instead", nil)
case IsOut(t):
return newResultObject(t, opts)
case embedsType(t, _outPtrType):
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot build a result object by embedding *dig.Out, embed dig.Out instead: %v embeds *dig.Out", t), nil)
case t.Kind() == reflect.Ptr && IsOut(t.Elem()):
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot return a pointer to a result object, use a value instead: %v is a pointer to a struct that embeds dig.Out", t), nil)
case len(opts.Group) > 0:
g, err := parseGroupString(opts.Group)
if err != nil {
return nil, newErrInvalidInput(
fmt.Sprintf("cannot parse group %q", opts.Group), err)
}
rg := resultGrouped{Type: t, Group: g.Name, Flatten: g.Flatten}
if len(opts.As) > 0 {
var asTypes []reflect.Type
for _, as := range opts.As {
ifaceType := reflect.TypeOf(as).Elem()
if ifaceType == t {
continue
}
if !t.Implements(ifaceType) {
return nil, newErrInvalidInput(
fmt.Sprintf("invalid dig.As: %v does not implement %v", t, ifaceType), nil)
}
asTypes = append(asTypes, ifaceType)
}
if len(asTypes) > 0 {
rg.Type = asTypes[0]
rg.As = asTypes[1:]
}
}
if g.Soft {
return nil, newErrInvalidInput(fmt.Sprintf(
"cannot use soft with result value groups: soft was used with group:%q", g.Name), nil)
}
if g.Flatten {
if t.Kind() != reflect.Slice {
return nil, newErrInvalidInput(fmt.Sprintf(
"flatten can be applied to slices only: %v is not a slice", t), nil)
}
rg.Type = rg.Type.Elem()
}
return rg, nil
default:
return newResultSingle(t, opts)
}
}
// resultVisitor visits every result in a result tree, allowing tracking state
// at each level.
type resultVisitor interface {
// Visit is called on the result being visited.
//
// If Visit returns a non-nil resultVisitor, that resultVisitor visits all
// the child results of this result.
Visit(result) resultVisitor
// AnnotateWithField is called on each field of a resultObject after
// visiting it but before walking its descendants.
//
// The same resultVisitor is used for all fields: the one returned upon
// visiting the resultObject.
//
// For each visited field, if AnnotateWithField returns a non-nil
// resultVisitor, it will be used to walk the result of that field.
AnnotateWithField(resultObjectField) resultVisitor
// AnnotateWithPosition is called with the index of each result of a
// resultList after vising it but before walking its descendants.
//
// The same resultVisitor is used for all results: the one returned upon
// visiting the resultList.
//
// For each position, if AnnotateWithPosition returns a non-nil
// resultVisitor, it will be used to walk the result at that index.
AnnotateWithPosition(idx int) resultVisitor
}
// walkResult walks the result tree for the given result with the provided
// visitor.
//
// resultVisitor.Visit will be called on the provided result and if a non-nil
// resultVisitor is received, it will be used to walk its descendants. If a
// resultObject or resultList was visited, AnnotateWithField and
// AnnotateWithPosition respectively will be called before visiting the
// descendants of that resultObject/resultList.
//
// This is very similar to how go/ast.Walk works.
func walkResult(r result, v resultVisitor) {
v = v.Visit(r)
if v == nil {
return
}
switch res := r.(type) {
case resultSingle, resultGrouped:
// No sub-results
case resultObject:
w := v
for _, f := range res.Fields {
if v := w.AnnotateWithField(f); v != nil {
walkResult(f.Result, v)
}
}
case resultList:
w := v
for i, r := range res.Results {
if v := w.AnnotateWithPosition(i); v != nil {
walkResult(r, v)
}
}
default:
digerror.BugPanicf("received unknown result type %T", res)
}
}
// resultList holds all values returned by the constructor as results.
type resultList struct {
ctype reflect.Type
Results []result
// For each item at index i returned by the constructor, resultIndexes[i]
// is the index in .Results for the corresponding result object.
// resultIndexes[i] is -1 for errors returned by constructors.
resultIndexes []int
}
func (rl resultList) DotResult() []*dot.Result {
var types []*dot.Result
for _, result := range rl.Results {
types = append(types, result.DotResult()...)
}
return types
}
func newResultList(ctype reflect.Type, opts resultOptions) (resultList, error) {
numOut := ctype.NumOut()
rl := resultList{
ctype: ctype,
Results: make([]result, 0, numOut),
resultIndexes: make([]int, numOut),
}
resultIdx := 0
for i := 0; i < numOut; i++ {
t := ctype.Out(i)
if isError(t) {
rl.resultIndexes[i] = -1
continue
}
r, err := newResult(t, opts)
if err != nil {
return rl, newErrInvalidInput(fmt.Sprintf("bad result %d", i+1), err)
}
rl.Results = append(rl.Results, r)
rl.resultIndexes[i] = resultIdx
resultIdx++
}
return rl, nil
}
func (resultList) Extract(containerWriter, bool, reflect.Value) {
digerror.BugPanicf("resultList.Extract() must never be called")
}
func (rl resultList) ExtractList(cw containerWriter, decorated bool, values []reflect.Value) error {
for i, v := range values {
if resultIdx := rl.resultIndexes[i]; resultIdx >= 0 {
rl.Results[resultIdx].Extract(cw, decorated, v)
continue
}
if err, _ := v.Interface().(error); err != nil {
return err
}
}
return nil
}
// resultSingle is an explicit value produced by a constructor, optionally
// with a name.
//
// This object will be added to the graph as-is.
type resultSingle struct {
Name string
Type reflect.Type
// If specified, this is a list of types which the value will be made
// available as, in addition to its own type.
As []reflect.Type
}
func newResultSingle(t reflect.Type, opts resultOptions) (resultSingle, error) {
r := resultSingle{
Type: t,
Name: opts.Name,
}
var asTypes []reflect.Type
for _, as := range opts.As {
ifaceType := reflect.TypeOf(as).Elem()
if ifaceType == t {
// Special case:
// c.Provide(func() io.Reader, As(new(io.Reader)))
// Ignore instead of erroring out.
continue
}
if !t.Implements(ifaceType) {
return r, newErrInvalidInput(
fmt.Sprintf("invalid dig.As: %v does not implement %v", t, ifaceType), nil)
}
asTypes = append(asTypes, ifaceType)
}
if len(asTypes) == 0 {
return r, nil
}
return resultSingle{
Type: asTypes[0],
Name: opts.Name,
As: asTypes[1:],
}, nil
}
func (rs resultSingle) DotResult() []*dot.Result {
dotResults := make([]*dot.Result, 0, len(rs.As)+1)
dotResults = append(dotResults, &dot.Result{
Node: &dot.Node{
Type: rs.Type,
Name: rs.Name,
},
})
for _, asType := range rs.As {
dotResults = append(dotResults, &dot.Result{
Node: &dot.Node{Type: asType, Name: rs.Name},
})
}
return dotResults
}
func (rs resultSingle) Extract(cw containerWriter, decorated bool, v reflect.Value) {
if decorated {
cw.setDecoratedValue(rs.Name, rs.Type, v)
return
}
cw.setValue(rs.Name, rs.Type, v)
for _, asType := range rs.As {
cw.setValue(rs.Name, asType, v)
}
}
// resultObject is a dig.Out struct where each field is another result.
//
// This object is not added to the graph. Its fields are interpreted as
// results and added to the graph if needed.
type resultObject struct {
Type reflect.Type
Fields []resultObjectField
}
func (ro resultObject) DotResult() []*dot.Result {
var types []*dot.Result
for _, field := range ro.Fields {
types = append(types, field.DotResult()...)
}
return types
}
func newResultObject(t reflect.Type, opts resultOptions) (resultObject, error) {
ro := resultObject{Type: t}
if len(opts.Name) > 0 {
return ro, newErrInvalidInput(fmt.Sprintf(
"cannot specify a name for result objects: %v embeds dig.Out", t), nil)
}
if len(opts.Group) > 0 {
return ro, newErrInvalidInput(fmt.Sprintf(
"cannot specify a group for result objects: %v embeds dig.Out", t), nil)
}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if f.Type == _outType {
// Skip over the dig.Out embed.
continue
}
rof, err := newResultObjectField(i, f, opts)
if err != nil {
return ro, newErrInvalidInput(fmt.Sprintf("bad field %q of %v", f.Name, t), err)
}
ro.Fields = append(ro.Fields, rof)
}
return ro, nil
}
func (ro resultObject) Extract(cw containerWriter, decorated bool, v reflect.Value) {
for _, f := range ro.Fields {
f.Result.Extract(cw, decorated, v.Field(f.FieldIndex))
}
}
// resultObjectField is a single field inside a dig.Out struct.
type resultObjectField struct {
// Name of the field in the struct.
FieldName string
// Index of the field in the struct.
//
// We need to track this separately because not all fields of the struct
// map to results.
FieldIndex int
// Result produced by this field.
Result result
}
func (rof resultObjectField) DotResult() []*dot.Result {
return rof.Result.DotResult()
}
// newResultObjectField(i, f, opts) builds a resultObjectField from the field
// f at index i.
func newResultObjectField(idx int, f reflect.StructField, opts resultOptions) (resultObjectField, error) {
rof := resultObjectField{
FieldName: f.Name,
FieldIndex: idx,
}
var r result
switch {
case f.PkgPath != "":
return rof, newErrInvalidInput(
fmt.Sprintf("unexported fields not allowed in dig.Out, did you mean to export %q (%v)?", f.Name, f.Type), nil)
case f.Tag.Get(_groupTag) != "":
var err error
r, err = newResultGrouped(f)
if err != nil {
return rof, err
}
default:
var err error
if name := f.Tag.Get(_nameTag); len(name) > 0 {
// can modify in-place because options are passed-by-value.
opts.Name = name
}
r, err = newResult(f.Type, opts)
if err != nil {
return rof, err
}
}
rof.Result = r
return rof, nil
}
// resultGrouped is a value produced by a constructor that is part of a result
// group.
//
// These will be produced as fields of a dig.Out struct.
type resultGrouped struct {
// Name of the group as specified in the `group:".."` tag.
Group string
// Type of value produced.
Type reflect.Type
// Indicates elements of a value are to be injected individually, instead of
// as a group. Requires the value's slice to be a group. If set, Type will be
// the type of individual elements rather than the group.
Flatten bool
// If specified, this is a list of types which the value will be made
// available as, in addition to its own type.
As []reflect.Type
}
func (rt resultGrouped) DotResult() []*dot.Result {
dotResults := make([]*dot.Result, 0, len(rt.As)+1)
dotResults = append(dotResults, &dot.Result{
Node: &dot.Node{
Type: rt.Type,
Group: rt.Group,
},
})
for _, asType := range rt.As {
dotResults = append(dotResults, &dot.Result{
Node: &dot.Node{Type: asType, Group: rt.Group},
})
}
return dotResults
}
// newResultGrouped(f) builds a new resultGrouped from the provided field.
func newResultGrouped(f reflect.StructField) (resultGrouped, error) {
g, err := parseGroupString(f.Tag.Get(_groupTag))
if err != nil {
return resultGrouped{}, err
}
rg := resultGrouped{
Group: g.Name,
Flatten: g.Flatten,
Type: f.Type,
}
name := f.Tag.Get(_nameTag)
optional, _ := isFieldOptional(f)
switch {
case g.Flatten && f.Type.Kind() != reflect.Slice:
return rg, newErrInvalidInput(fmt.Sprintf(
"flatten can be applied to slices only: field %q (%v) is not a slice", f.Name, f.Type), nil)
case g.Soft:
return rg, newErrInvalidInput(fmt.Sprintf(
"cannot use soft with result value groups: soft was used with group %q", rg.Group), nil)
case name != "":
return rg, newErrInvalidInput(fmt.Sprintf(
"cannot use named values with value groups: name:%q provided with group:%q", name, rg.Group), nil)
case optional:
return rg, newErrInvalidInput("value groups cannot be optional", nil)
}
if g.Flatten {
rg.Type = f.Type.Elem()
}
return rg, nil
}
func (rt resultGrouped) Extract(cw containerWriter, decorated bool, v reflect.Value) {
// Decorated values are always flattened.
if !decorated && !rt.Flatten {
cw.submitGroupedValue(rt.Group, rt.Type, v)
for _, asType := range rt.As {
cw.submitGroupedValue(rt.Group, asType, v)
}
return
}
if decorated {
cw.submitDecoratedGroupedValue(rt.Group, rt.Type, v)
return
}
for i := 0; i < v.Len(); i++ {
cw.submitGroupedValue(rt.Group, rt.Type, v.Index(i))
}
}

326
vendor/go.uber.org/dig/scope.go generated vendored Normal file
View File

@@ -0,0 +1,326 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"bytes"
"fmt"
"math/rand"
"reflect"
"sort"
"time"
)
// A ScopeOption modifies the default behavior of Scope; currently,
// there are no implementations.
type ScopeOption interface {
noScopeOption() //yet
}
// Scope is a scoped DAG of types and their dependencies.
// A Scope may also have one or more child Scopes that inherit
// from it.
type Scope struct {
// This implements containerStore interface.
// Name of the Scope
name string
// Mapping from key to all the constructor node that can provide a value for that
// key.
providers map[key][]*constructorNode
// Mapping from key to the decorator that decorates a value for that key.
decorators map[key]*decoratorNode
// constructorNodes provided directly to this Scope. i.e. it does not include
// any nodes that were provided to the parent Scope this inherited from.
nodes []*constructorNode
// Values that generated via decorators in the Scope.
decoratedValues map[key]reflect.Value
// Values that generated directly in the Scope.
values map[key]reflect.Value
// Values groups that generated directly in the Scope.
groups map[key][]reflect.Value
// Values groups that generated via decoraters in the Scope.
decoratedGroups map[key]reflect.Value
// Source of randomness.
rand *rand.Rand
// Flag indicating whether the graph has been checked for cycles.
isVerifiedAcyclic bool
// Defer acyclic check on provide until Invoke.
deferAcyclicVerification bool
// Recover from panics in user-provided code and wrap in an exported error type.
recoverFromPanics bool
// invokerFn calls a function with arguments provided to Provide or Invoke.
invokerFn invokerFn
// graph of this Scope. Note that this holds the dependency graph of all the
// nodes that affect this Scope, not just the ones provided directly to this Scope.
gh *graphHolder
// Parent of this Scope.
parentScope *Scope
// All the child scopes of this Scope.
childScopes []*Scope
}
func newScope() *Scope {
s := &Scope{
providers: make(map[key][]*constructorNode),
decorators: make(map[key]*decoratorNode),
values: make(map[key]reflect.Value),
decoratedValues: make(map[key]reflect.Value),
groups: make(map[key][]reflect.Value),
decoratedGroups: make(map[key]reflect.Value),
invokerFn: defaultInvoker,
rand: rand.New(rand.NewSource(time.Now().UnixNano())),
}
s.gh = newGraphHolder(s)
return s
}
// Scope creates a new Scope with the given name and options from current Scope.
// Any constructors that the current Scope knows about, as well as any modifications
// made to it in the future will be propagated to the child scope.
// However, no modifications made to the child scope being created will be propagated
// to the parent Scope.
func (s *Scope) Scope(name string, opts ...ScopeOption) *Scope {
child := newScope()
child.name = name
child.parentScope = s
child.invokerFn = s.invokerFn
child.deferAcyclicVerification = s.deferAcyclicVerification
child.recoverFromPanics = s.recoverFromPanics
// child copies the parent's graph nodes.
for _, node := range s.gh.nodes {
child.gh.nodes = append(child.gh.nodes, node)
if ctrNode, ok := node.Wrapped.(*constructorNode); ok {
ctrNode.CopyOrder(s, child)
}
}
for _, opt := range opts {
opt.noScopeOption()
}
s.childScopes = append(s.childScopes, child)
return child
}
// ancestors returns a list of scopes of ancestors of this scope up to the
// root. The scope at at index 0 is this scope itself.
func (s *Scope) ancestors() []*Scope {
var scopes []*Scope
for s := s; s != nil; s = s.parentScope {
scopes = append(scopes, s)
}
return scopes
}
func (s *Scope) appendSubscopes(dest []*Scope) []*Scope {
dest = append(dest, s)
for _, cs := range s.childScopes {
dest = cs.appendSubscopes(dest)
}
return dest
}
func (s *Scope) storesToRoot() []containerStore {
scopes := s.ancestors()
stores := make([]containerStore, len(scopes))
for i, s := range scopes {
stores[i] = s
}
return stores
}
func (s *Scope) knownTypes() []reflect.Type {
typeSet := make(map[reflect.Type]struct{}, len(s.providers))
for k := range s.providers {
typeSet[k.t] = struct{}{}
}
types := make([]reflect.Type, 0, len(typeSet))
for t := range typeSet {
types = append(types, t)
}
sort.Sort(byTypeName(types))
return types
}
func (s *Scope) getValue(name string, t reflect.Type) (v reflect.Value, ok bool) {
v, ok = s.values[key{name: name, t: t}]
return
}
func (s *Scope) getDecoratedValue(name string, t reflect.Type) (v reflect.Value, ok bool) {
v, ok = s.decoratedValues[key{name: name, t: t}]
return
}
func (s *Scope) setValue(name string, t reflect.Type, v reflect.Value) {
s.values[key{name: name, t: t}] = v
}
func (s *Scope) setDecoratedValue(name string, t reflect.Type, v reflect.Value) {
s.decoratedValues[key{name: name, t: t}] = v
}
func (s *Scope) getValueGroup(name string, t reflect.Type) []reflect.Value {
items := s.groups[key{group: name, t: t}]
// shuffle the list so users don't rely on the ordering of grouped values
return shuffledCopy(s.rand, items)
}
func (s *Scope) getDecoratedValueGroup(name string, t reflect.Type) (reflect.Value, bool) {
items, ok := s.decoratedGroups[key{group: name, t: t}]
return items, ok
}
func (s *Scope) submitGroupedValue(name string, t reflect.Type, v reflect.Value) {
k := key{group: name, t: t}
s.groups[k] = append(s.groups[k], v)
}
func (s *Scope) submitDecoratedGroupedValue(name string, t reflect.Type, v reflect.Value) {
k := key{group: name, t: t}
s.decoratedGroups[k] = v
}
func (s *Scope) getValueProviders(name string, t reflect.Type) []provider {
return s.getProviders(key{name: name, t: t})
}
func (s *Scope) getGroupProviders(name string, t reflect.Type) []provider {
return s.getProviders(key{group: name, t: t})
}
func (s *Scope) getValueDecorator(name string, t reflect.Type) (decorator, bool) {
return s.getDecorators(key{name: name, t: t})
}
func (s *Scope) getGroupDecorator(name string, t reflect.Type) (decorator, bool) {
return s.getDecorators(key{group: name, t: t})
}
func (s *Scope) getDecorators(k key) (decorator, bool) {
d, found := s.decorators[k]
return d, found
}
func (s *Scope) getProviders(k key) []provider {
nodes := s.providers[k]
providers := make([]provider, len(nodes))
for i, n := range nodes {
providers[i] = n
}
return providers
}
func (s *Scope) getAllGroupProviders(name string, t reflect.Type) []provider {
return s.getAllProviders(key{group: name, t: t})
}
func (s *Scope) getAllValueProviders(name string, t reflect.Type) []provider {
return s.getAllProviders(key{name: name, t: t})
}
func (s *Scope) getAllProviders(k key) []provider {
allScopes := s.ancestors()
var providers []provider
for _, scope := range allScopes {
providers = append(providers, scope.getProviders(k)...)
}
return providers
}
func (s *Scope) invoker() invokerFn {
return s.invokerFn
}
// adds a new graphNode to this Scope and all of its descendent
// scope.
func (s *Scope) newGraphNode(wrapped interface{}, orders map[*Scope]int) {
orders[s] = s.gh.NewNode(wrapped)
for _, cs := range s.childScopes {
cs.newGraphNode(wrapped, orders)
}
}
func (s *Scope) cycleDetectedError(cycle []int) error {
var path []cycleErrPathEntry
for _, n := range cycle {
if n, ok := s.gh.Lookup(n).(*constructorNode); ok {
path = append(path, cycleErrPathEntry{
Key: key{
t: n.CType(),
},
Func: n.Location(),
})
}
}
return errCycleDetected{Path: path, scope: s}
}
// Returns the root Scope that can be reached from this Scope.
func (s *Scope) rootScope() *Scope {
curr := s
for curr.parentScope != nil {
curr = curr.parentScope
}
return curr
}
// String representation of the entire Scope
func (s *Scope) String() string {
b := &bytes.Buffer{}
fmt.Fprintln(b, "nodes: {")
for k, vs := range s.providers {
for _, v := range vs {
fmt.Fprintln(b, "\t", k, "->", v)
}
}
fmt.Fprintln(b, "}")
fmt.Fprintln(b, "values: {")
for k, v := range s.values {
fmt.Fprintln(b, "\t", k, "=>", v)
}
for k, vs := range s.groups {
for _, v := range vs {
fmt.Fprintln(b, "\t", k, "=>", v)
}
}
fmt.Fprintln(b, "}")
return b.String()
}

24
vendor/go.uber.org/dig/version.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
// Version of the library.
const Version = "1.17.1"

192
vendor/go.uber.org/dig/visualize.go generated vendored Normal file
View File

@@ -0,0 +1,192 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package dig
import (
"errors"
"fmt"
"io"
"strconv"
"text/template"
"go.uber.org/dig/internal/dot"
)
// A VisualizeOption modifies the default behavior of Visualize.
type VisualizeOption interface {
applyVisualizeOption(*visualizeOptions)
}
type visualizeOptions struct {
VisualizeError error
}
// VisualizeError includes a visualization of the given error in the output of
// Visualize if an error was returned by Invoke or Provide.
//
// if err := c.Provide(...); err != nil {
// dig.Visualize(c, w, dig.VisualizeError(err))
// }
//
// This option has no effect if the error was nil or if it didn't contain any
// information to visualize.
func VisualizeError(err error) VisualizeOption {
return visualizeErrorOption{err}
}
type visualizeErrorOption struct{ err error }
func (o visualizeErrorOption) String() string {
return fmt.Sprintf("VisualizeError(%v)", o.err)
}
func (o visualizeErrorOption) applyVisualizeOption(opt *visualizeOptions) {
opt.VisualizeError = o.err
}
func updateGraph(dg *dot.Graph, err error) error {
var errs []errVisualizer
// Unwrap error to find the root cause.
for {
if ev, ok := err.(errVisualizer); ok {
errs = append(errs, ev)
}
e := errors.Unwrap(err)
if e == nil {
break
}
err = e
}
// If there are no errVisualizers included, we do not modify the graph.
if len(errs) == 0 {
return nil
}
// We iterate in reverse because the last element is the root cause.
for i := len(errs) - 1; i >= 0; i-- {
errs[i].updateGraph(dg)
}
// Remove non-error entries from the graph for readability.
dg.PruneSuccess()
return nil
}
var _graphTmpl = template.Must(
template.New("DotGraph").
Funcs(template.FuncMap{
"quote": strconv.Quote,
}).
Parse(`digraph {
rankdir=RL;
graph [compound=true];
{{range $g := .Groups}}
{{- quote .String}} [{{.Attributes}}];
{{range .Results}}
{{- quote $g.String}} -> {{quote .String}};
{{end}}
{{end -}}
{{range $index, $ctor := .Ctors}}
subgraph cluster_{{$index}} {
{{ with .Package }}label = {{ quote .}};
{{ end -}}
constructor_{{$index}} [shape=plaintext label={{quote .Name}}];
{{with .ErrorType}}color={{.Color}};{{end}}
{{range .Results}}
{{- quote .String}} [{{.Attributes}}];
{{end}}
}
{{range .Params}}
constructor_{{$index}} -> {{quote .String}} [ltail=cluster_{{$index}}{{if .Optional}} style=dashed{{end}}];
{{end}}
{{range .GroupParams}}
constructor_{{$index}} -> {{quote .String}} [ltail=cluster_{{$index}}];
{{end -}}
{{end}}
{{range .Failed.TransitiveFailures}}
{{- quote .String}} [color=orange];
{{end -}}
{{range .Failed.RootCauses}}
{{- quote .String}} [color=red];
{{end}}
}`))
// Visualize parses the graph in Container c into DOT format and writes it to
// io.Writer w.
func Visualize(c *Container, w io.Writer, opts ...VisualizeOption) error {
dg := c.createGraph()
var options visualizeOptions
for _, o := range opts {
o.applyVisualizeOption(&options)
}
if options.VisualizeError != nil {
if err := updateGraph(dg, options.VisualizeError); err != nil {
return err
}
}
return _graphTmpl.Execute(w, dg)
}
// CanVisualizeError returns true if the error is an errVisualizer.
func CanVisualizeError(err error) bool {
for {
if _, ok := err.(errVisualizer); ok {
return true
}
e := errors.Unwrap(err)
if e == nil {
break
}
err = e
}
return false
}
func (c *Container) createGraph() *dot.Graph {
return c.scope.createGraph()
}
func (s *Scope) createGraph() *dot.Graph {
dg := dot.NewGraph()
for _, n := range s.nodes {
dg.AddCtor(newDotCtor(n), n.paramList.DotParam(), n.resultList.DotResult())
}
return dg
}
func newDotCtor(n *constructorNode) *dot.Ctor {
return &dot.Ctor{
ID: n.id,
Name: n.location.Name,
Package: n.location.Package,
File: n.location.File,
Line: n.location.Line,
}
}

18
vendor/go.uber.org/fx/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,18 @@
ignore:
- "docs/ex/**/*.go"
- "internal/e2e/**/*.go"
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 90% # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

16
vendor/go.uber.org/fx/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/vendor
/.bench
*.mem
*.cpu
*.test
*.log
*.out
*.html
*.coverprofile
coverage.txt
*.pprof
/.bin
/.cache
/bin
.vscode
.mdoxcache

409
vendor/go.uber.org/fx/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,409 @@
---
sidebarDepth: 0
search: false
---
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.20.1](https://github.com/uber-go/fx/compare/v1.20.0...v1.20.1) - 2023-10-17
### Added
- Provided, Decorated, Supplied, and Replaced events now include a trace
of module locations through which the option was given to the App.
- wasi support.
## [1.20.0](https://github.com/uber-go/fx/compare/v1.19.3...v1.20.0) - 2023-06-12
### Added
- A new event `fxevent.Run` is now emitted when Fx runs a constructor, decorator,
or supply/replace stub.
### Changed
- `fx.Populate` now works with `fx.Annotate`.
- Upgrade Dig dependency to v1.17.0.
## [1.19.3](https://github.com/uber-go/fx/compare/v1.19.2...v1.19.3) - 2023-04-17
### Changed
- Fixed several typos in docs.
- WASM build support.
- Annotating In and Out structs with From/As annotations generated invalid results.
The annotation check now blocks this.
- `Shutdown`: Support calling from `Invoke`.
### Deprecated
- Deprecate `ShutdownTimeout` option.
### Fixed
- Respect Shutdowner ExitCode from calling `Run`.
## [1.19.2](https://github.com/uber-go/fx/compare/v1.19.1...v1.19.2) - 2023-02-21
### Changed
- Update Dig dependency to v1.16.1.
## [1.19.1](https://github.com/uber-go/fx/compare/v1.19.0...v1.19.1) - 2023-01-10
### Changed
- Calling `fx.Stop()` after the `App` has already stopped no longer errors out.
### Fixed
- Addressed a regression in 1.19.0 release which caused apps to ignore OS signals
after running for startTimeout duration.
## [1.19.0](https://github.com/uber-go/fx/compare/v1.18.2...v1.19.0) - 2023-01-03
### Added
- `fx.RecoverFromPanics` Option which allows Fx to recover from user-provided constructors
and invoked functions.
- `fx.Private` that allows the constructor to limit the scope of its outputs to the wrapping
`fx.Module`.
- `ExitCode` ShutdownOption which allows setting custom exit code at the end of app
lifecycle.
- `Wait` which returns a channel that can be used for waiting on application shutdown.
- fxevent/ZapLogger now exposes `UseLogLevel` and `UseErrorLevel` methods to set
the level of the Zap logs produced by it.
- Add lifecycle hook-convertible methods: `StartHook`, `StopHook`, `StartStopHook`
that can be used with more function signatures.
### Changed
- `fx.WithLogger` can now be passed at `fx.Module` level, setting custom logger at
`Module` scope instead of the whole `App`.
### Fixed
- `fx.OnStart` and `fx.OnStop` Annotations now work with annotated types that was
provided by the annotated constructor.
- fxevent/ZapLogger: Errors from `fx.Supply` are now logged at `Error` level, not
`Info`.
- A race condition in lifecycle Start/Stop methods.
- Typos in docs.
## [1.18.2](https://github.com/uber-go/fx/compare/v1.18.1...v1.18.2) - 2022-09-28
### Added
- Clarify ordering of `Invoke`s in `Module`s.
### Fixed
- Fix `Decorate` not being applied to transitive dependencies at root `App` level.
## [1.18.1](https://github.com/uber-go/fx/compare/v1.18.0...v1.18.1) - 2022-08-08
### Fixed
- Fix a nil panic when `nil` is passed to `OnStart` and `OnStop` lifecycle methods.
## [1.18.0](https://github.com/uber-go/fx/compare/v1.17.1...v1.18.0) - 2022-08-05
### Added
- Soft value groups that lets you specify value groups as best-effort dependencies.
- `fx.OnStart` and `fx.OnStop` annotations which lets you annotate dependencies to provide
OnStart and OnStop lifecycle hooks.
- A new `fxevent.Replaced` event written to `fxevent.Logger` following an `fx.Replace`.
### Fixed
- Upgrade Dig dependency to v1.14.1 to address a couple of issues with decorations. Refer to
Dig v1.14.1 release notes for more details.
- `fx.WithLogger` no longer ignores decorations and replacements of types that
it depends on.
- Don't run lifecycle hooks if the context for them has already expired.
- `App.Start` and `App.Stop` no longer deadlock if the OnStart/OnStop hook
exits the current goroutine.
- `fxevent.ConsoleLogger` no longer emits an extraneous argument for the
Supplied event.
### Deprecated
- `fx.Extract` in favor of `fx.Populate`.
## [1.17.1](https://github.com/uber-go/fx/compare/v1.17.0...v1.17.1) - 2022-03-23
### Added
- Logging for provide/invoke/decorate now includes the associated `fx.Module` name.
## [1.17.0](https://github.com/uber-go/fx/compare/v1.16.0...v1.17.0) - 2022-02-28
### Added
- Add `fx.Module` which scopes any modifications made to the dependency graph.
- Add `fx.Decorate` and `fx.Replace` that lets you modify a dependency graph with decorators.
- Add `fxevent.Decorated` event which gets emitted upon a dependency getting decorated.
### Changed
- `fx.Annotate`: Validate that `fx.In` or `fx.Out` structs are not passed to it.
- `fx.Annotate`: Upon failure to Provide, the error contains the actual location
of the provided constructor.
## [1.16.0](https://github.com/uber-go/fx/compare/v1.15.0...v1.16.0) - 2021-12-02
### Added
- Add the ability to provide a function as multiple interfaces at once using `fx.As`.
### Changed
- `fx.Annotate`: support variadic functions, and feeding value groups into them.
### Fixed
- Fix an issue where OnStop hooks weren't getting called on SIGINT on Windows.
- Fix a data race between app.Done() and shutdown.
## [1.15.0](https://github.com/uber-go/fx/compare/v1.14.2...v1.15.0) - 2021-11-08
### Added
- Add `fx.Annotate` to allow users to provide parameter and result tags easily without
having to create `fx.In` or `fx.Out` structs.
- Add `fx.As` that allows users to annotate a constructor to provide its result type(s) as
interface(s) that they implement instead of the types themselves.
### Fixed
- Fix `fxevent.Stopped` not being logged when `App.Stop` is called.
- Fix `fxevent.Started` or `fxevent.Stopped` not being logged when start or
stop times out.
## [1.14.2](https://github.com/uber-go/fx/compare/v1.14.1...v1.14.2) - 2021-08-16
### Changed
- For `fxevent` console implementation: no longer log non-error case for `fxevent.Invoke`
event, while for zap implementation, start logging `fx.Invoking` case without stack.
## [1.14.1](https://github.com/uber-go/fx/compare/v1.14.0...v1.14.1) - 2021-08-16
### Changed
- `fxevent.Invoked` was being logged at `Error` level even upon successful `Invoke`.
This was changed to log at `Info` level when `Invoke` succeeded.
## [1.14.0](https://github.com/uber-go/fx/compare/v1.13.1...v1.14.0) - 2021-08-12
### Added
- Introduce the new `fx.WithLogger` option. Provide a constructor for
`fxevent.Logger` objects with it to customize how Fx logs events.
- Add new `fxevent` package that exposes events from Fx in a structured way.
Use this to write custom logger implementations for use with the
`fx.WithLogger` option.
- Expose and log additional information when lifecycle hooks time out.
### Changed
- Fx now emits structured JSON logs by default. These may be parsed and
processed by log ingestion systems.
- `fxtest.Lifecycle` now logs to the provided `testing.TB` instead of stderr.
- `fx.In` and `fx.Out` are now type aliases instead of structs.
## [1.13.1](https://github.com/uber-go/fx/compare/v1.13.0...v1.13.1) - 2020-08-19
### Fixed
- Fix minimum version constraint for dig. `fx.ValidateGraph` requires at least
dig 1.10.
## [1.13.0](https://github.com/uber-go/fx/compare/v1.12.0...v1.13.0) - 2020-06-16
### Added
- Added `fx.ValidateGraph` which allows graph cycle validation and dependency correctness
without running anything. This is useful if `fx.Invoke` has side effects, does I/O, etc.
## [1.12.0](https://github.com/uber-go/fx/compare/v1.11.0...v1.12.0) - 2020-04-09
### Added
- Added `fx.Supply` to provide externally created values to Fx containers
without building anonymous constructors.
### Changed
- Drop library dependency on development tools.
## [1.11.0](https://github.com/uber-go/fx/compare/v1.10.0...v1.11.0) - 2020-04-01
### Added
- Value groups can use the `flatten` option to indicate values in a slice should
be provided individually rather than providing the slice itself. See package
documentation for details.
## [1.10.0](https://github.com/uber-go/fx/compare/v1.9.0...v1.10.0) - 2019-11-20
### Added
- All `fx.Option`s now include readable string representations.
- Report stack traces when `fx.Provide` and `fx.Invoke` calls fail. This
should make these errors more debuggable.
### Changed
- Migrated to Go modules.
## [1.9.0](https://github.com/uber-go/fx/compare/v1.8.0...v1.9.0) - 2019-01-22
### Added
- Add the ability to shutdown Fx applications from inside the container. See
the Shutdowner documentation for details.
- Add `fx.Annotated` to allow users to provide named values without creating a
new constructor.
## [1.8.0](https://github.com/uber-go/fx/compare/v1.7.1...v1.8.0) - 2018-11-06
### Added
- Provide DOT graph of dependencies in the container.
## [1.7.1](https://github.com/uber-go/fx/compare/v1.7.0...v1.7.1) - 2018-09-26
### Fixed
- Make `fxtest.New` ensure that the app was created successfully. Previously,
it would return the app (similar to `fx.New`, which expects the user to verify
the error).
- Update dig container to defer acyclic validation until after Invoke. Application
startup time should improve proportional to the size of the dependency graph.
- Fix a goroutine leak in `fxtest.Lifecycle`.
## [1.7.0](https://github.com/uber-go/fx/compare/v1.6.0...v1.7.0) - 2018-08-16
### Added
- Add `fx.ErrorHook` option to allow users to provide `ErrorHandler`s on invoke
failures.
- `VisualizeError` returns the visualization wrapped in the error if available.
## [1.6.0](https://github.com/uber-go/fx/compare/v1.5.0...v1.6.0) - 2018-06-12
### Added
- Add `fx.Error` option to short-circuit application startup.
## [1.5.0](https://github.com/uber-go/fx/compare/v1.4.0...v1.5.0) - 2018-04-11
### Added
- Add `fx.StartTimeout` and `fx.StopTimeout` to make configuring application
start and stop timeouts easier.
- Export the default start and stop timeout as `fx.DefaultTimeout`.
### Fixed
- Make `fxtest` respect the application's start and stop timeouts.
## [1.4.0](https://github.com/uber-go/fx/compare/v1.3.0...v1.4.0) - 2017-12-07
### Added
- Add `fx.Populate` to populate variables with values from the dependency
injection container without requiring intermediate structs.
## [1.3.0](https://github.com/uber-go/fx/compare/v1.2.0...v1.3.0) - 2017-11-28
### Changed
- Improve readability of hook logging in addition to provide and invoke.
### Fixed
- Fix bug which caused the OnStop for a lifecycle hook to be called even if it
failed to start.
## [1.2.0](https://github.com/uber-go/fx/compare/v1.1.0...v1.2.0) - 2017-09-06
### Added
- Add `fx.NopLogger` which disables the Fx application's log output.
## [1.1.0](https://github.com/uber-go/fx/compare/v1.0.0...v1.1.0) - 2017-08-22
### Changed
- Improve readability of start up logging.
## [1.0.0](https://github.com/uber-go/fx/compare/v1.0.0-rc2...v1.0.0) - 2017-07-31
First stable release: no breaking changes will be made in the 1.x series.
### Added
- `fx.Extract` now supports `fx.In` tags on target structs.
### Changed
- **[Breaking]** Rename `fx.Inject` to `fx.Extract`.
- **[Breaking]** Rename `fxtest.Must*` to `fxtest.Require*`.
### Removed
- **[Breaking]** Remove `fx.Timeout` and `fx.DefaultTimeout`.
## [1.0.0-rc2](https://github.com/uber-go/fx/compare/v1.0.0-rc1...v1.0.0-rc2) - 2017-07-21
- **[Breaking]** Lifecycle hooks now take a context.
- Add `fx.In` and `fx.Out` which exposes optional and named types.
Modules should embed these types instead of relying on `dig.In` and `dig.Out`.
- Add an `Err` method to retrieve the underlying errors during the dependency
graph construction. The same error is also returned from `Start`.
- Graph resolution now happens as part of `fx.New`, rather than at the beginning
of `app.Start`. This allows inspection of the graph errors through `app.Err()`
before the decision to start the app.
- Add a `Logger` option, which allows users to send Fx's logs to different
sink.
- Add `fxtest.App`, which redirects log output to the user's `testing.TB` and
provides some lifecycle helpers.
## [1.0.0-rc1](https://github.com/uber-go/fx/compare/v1.0.0-beta4...v1.0.0-rc1) - 2017-06-20
- **[Breaking]** Providing types into `fx.App` and invoking functions are now
options passed during application construction. This makes users'
interactions with modules and collections of modules identical.
- **[Breaking]** `TestLifecycle` is now in a separate `fxtest` subpackage.
- Add `fx.Inject()` to pull values from the container into a struct.
## [1.0.0-beta4](https://github.com/uber-go/fx/compare/v1.0.0-beta3...v1.0.0-beta4) - 2017-06-12
- **[Breaking]** Monolithic framework, as released in initial betas, has been
broken into smaller pieces as a result of recent advances in `dig` library.
This is a radical departure from the previous direction, but it needed to
be done for the long-term good of the project.
- **[Breaking]** `Module interface` has been scoped all the way down to being
*a single dig constructor*. This allows for very sophisticated module
compositions. See `go.uber.org/dig` for more information on the constructors.
- **[Breaking]** `package config` has been moved to its own repository.
see `go.uber.org/config` for more information.
- `fx.Lifecycle` has been added for modules to hook into the framework
lifecycle events.
- `service.Host` interface which composed a number of primitives together
(configuration, metrics, tracing) has been deprecated in favor of
`fx.App`.
## [1.0.0-beta3](https://github.com/uber-go/fx/compare/v1.0.0-beta2...v1.0.0-beta3) - 2017-03-28
- **[Breaking]** Environment config provider was removed. If you were using
environment variables to override YAML values, see config documentation for
more information.
- **[Breaking]** Simplify Provider interface: remove `Scope` method from the
`config.Provider` interface, one can use either ScopedProvider and Value.Get()
to access sub fields.
- Add `task.MustRegister` convenience function which fails fast by panicking
Note that this should only be used during app initialization, and is provided
to avoid repetetive error checking for services which register many tasks.
- Expose options on task module to disable execution. This will allow users to
enqueue and consume tasks on different clusters.
- **[Breaking]** Rename Backend interface `Publish` to `Enqueue`. Created a new
`ExecuteAsync` method that will kick off workers to consume tasks and this is
subsumed by module Start.
- **[Breaking]** Rename package `uhttp/client` to `uhttp/uhttpclient` for clarity.
- **[Breaking]** Rename `PopulateStruct` method in value to `Populate`.
The method can now populate not only structs, but anything: slices,
maps, builtin types and maps.
- **[Breaking]** `package dig` has moved from `go.uber.org/fx/dig` to a new home
at `go.uber.org/dig`.
- **[Breaking]** Pass a tracer the `uhttp/uhttpclient` constructor explicitly, instead
of using a global tracer. This will allow to use http client in parallel tests.
## [1.0.0-beta2](https://github.com/uber-go/fx/compare/v1.0.0-beta1...v1.0.0-beta2) - 2017-03-09
- **[Breaking]** Remove `ulog.Logger` interface and expose `*zap.Logger` directly.
- **[Breaking]** Rename config and module from `modules.rpc` to `modules.yarpc`
- **[Breaking]** Rename config key from `modules.http` to `modules.uhttp` to match
the module name
- **[Breaking]** Upgrade `zap` to `v1.0.0-rc.3` (now go.uber.org/zap, was
github.com/uber-go/zap)
- Remove now-unused `config.IsDevelopmentEnv()` helper to encourage better
testing practices. Not a breaking change as nobody is using this func
themselves according to our code search tool.
- Log `traceID` and `spanID` in hex format to match Jaeger UI. Upgrade Jaeger to
min version 2.1.0
and use jaeger's adapters for jaeger and tally initialization.
- Tally now supports reporting histogram samples for a bucket. Upgrade Tally to 2.1.0
- **[Breaking]** Make new module naming consistent `yarpc.ThriftModule` to
`yarpc.New`, `task.NewModule`
to `task.New`
- **[Breaking]** Rename `yarpc.CreateThriftServiceFunc` to `yarpc.ServiceCreateFunc`
as it is not thrift-specific.
- Report version metrics for company-wide version usage information.
- Allow configurable service name and module name via service options.
- DIG constructors now support returning a tuple with the second argument being
an error.
## 1.0.0-beta1 - 2017-02-20
This is the first beta release of the framework, where we invite users to start
building services on it and provide us feedback. **Warning** we are not
promising API compatibility between beta releases and the final 1.0.0 release.
In fact, we expect our beta user feedback to require some changes to the way
things work. Once we reach 1.0, we will provider proper version compatibility.

291
vendor/go.uber.org/fx/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,291 @@
---
sidebarDepth: 2
search: false
---
# Contributing
Thanks for helping to make Fx better for everyone!
If you'd like to add new exported APIs,
please [open an issue](https://github.com/uber-go/fx/issues/new)
describing your proposal.
Discussing API changes ahead of time makes pull request review much smoother.
::: tip
You'll need to sign [Uber's CLA](https://cla-assistant.io/uber-go/fx)
before we can accept any of your contributions.
If necessary, a bot will remind
you to accept the CLA when you open your pull request.
:::
## Contribute code
Set up your local development environment to contribute to Fx.
1. [Fork](https://github.com/uber-go/fx/fork), then clone the repository.
<code-group>
<code-block title="Git">
```bash
git clone https://github.com/your_github_username/fx.git
cd fx
git remote add upstream https://github.com/uber-go/fx.git
git fetch upstream
```
</code-block>
<code-block title="GitHub CLI">
```bash
gh repo fork --clone uber-go/fx
```
</code-block>
</code-group>
2. Install Fx's dependencies:
```bash
go mod download
```
3. Verify that tests and other checks pass locally.
```bash
make lint
make test
```
Note that for `make lint` to work,
you must be using the latest stable version of Go.
If you're on an older version, you can still contribute your change,
but we may discover style violations when you open the pull request.
Next, make your changes.
1. Create a new feature branch.
```bash
git checkout master
git pull
git checkout -b cool_new_feature
```
2. Make your changes, and verify that all tests and lints still pass.
```bash
$EDITOR app.go
make lint
make test
```
3. When you're satisfied with the change,
push it to your fork and make a pull request.
<code-group>
<code-block title="Git">
```bash
git push origin cool_new_feature
# Open a PR at https://github.com/uber-go/fx/compare
```
</code-block>
<code-block title="GitHub CLI">
```bash
gh pr create
```
</code-block>
</code-group>
At this point, you're waiting on us to review your changes.
We *try* to respond to issues and pull requests within a few business days,
and we may suggest some improvements or alternatives.
Once your changes are approved, one of the project maintainers will merge them.
The review process will go more smoothly if you:
- add tests for new functionality
- write a [good commit message](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
- maintain backward compatibility
- follow our [style guide](https://github.com/uber-go/guide/blob/master/style.md)
## Contribute documentation
To contribute documentation to Fx,
1. Set up your local development environment
as you would to [contribute code](#contribute-code).
2. Install the documentation website dependencies.
```bash
cd docs
yarn install
```
3. Run the development server.
```bash
yarn dev
```
4. Make your changes.
Documentation changes should adhere to the guidance laid out below.
### Document by purpose
Documentation is organized in one of the following categories.
- **Tutorials**: These hold step-by-step instructions for an end-to-end project
that a beginner could follow along to.
Don't spend time explaining things.
If explanations are available elsewhere, link to them.
These are entry points to answer the prompt,
"I don't know what Fx is, show me what it can do,"
so there won't be too many of these.
- **Explanations**: These hold long-form explanations of concepts and ideas.
These are intended to build an understanding of Fx.
Feel free to go wild here--use learning aids like diagrams, tables, etc.
- **How-tos**: These are step-by-step instructions for a *specific problem*.
Unlike tutorials, these are not meant to be end-to-end.
Feel free to leave things out, make assumptions,
or provide options ("if you're doing this, do this").
As with tutorials, don't spend time explaining;
link to explanations elsewhere.
As an example,
- A tutorial will use lifecycle hooks as part of
a larger set of instructions for a full end-to-end application.
- An explanation will explain what lifecycle hooks are, how they work,
when and how you should use them, and link to relevant APIs and guides.
- A how-to guide will demonstrate how to use lifecycle hooks
with an HTTP server, a gRPC server, etc.
Explanations and how-to guides are often on the same page,
but they should be in distinct sections.
This separation is inspired by the
[Divio documentation system](https://documentation.divio.com/),
### Formatting
#### ATX-style headers
Use ATX-style headers (`#`-prefixed),
not Setext-style (underlined with `===` or `---`).
```markdown
Bad header
==========
## Good header
```
#### Semantic Line Breaks
- **Do not** write overly long lines of text
- **Do not** "reflow" Markdown paragraphs
- **Do** use [Semantic Line Breaks](https://sembr.org/) to break these lines down
```markdown
This is a bad paragraph because it's really long, all on one line. When I open this in a text editor, I'll have to scroll right.
This is a bad paragraph because even though it's not all one one line, it adds
line breaks when it reaches the line length limit. This means that anytime I
change anything in this paragraph, I have to "reflow" it, which will change
other lines and make the change I'm making more difficult to review.
This is a good paragraph. It uses semantic line breaks.
I can add words or modify an existing sentence,
or even parts of a sentence,
easily and without affecting other lines.
When I change something, the actual change I made is easy to review.
Markdown will reflow this into a "normal" pargraph when rendering.
```
### Test everything
All code samples in documentation must be buildable and testable.
To aid in this, we have two tools:
- [mdox](https://github.com/bwplotka/mdox/)
- the `region` shell script
#### mdox
mdox is a Markdown file formatter that includes support for
running a command and using its output as part of a code block.
To use this, declare a regular code block and tag it with `mdoc-exec`.
```markdown
```go mdox-exec='cat foo.go'
// ...
```
The contents of the code block will be replaced
with the output of the command when you run `make fmt`
in the docs directory.
`make check` will ensure that the contents are up-to-date.
The command runs with the working directory set to docs/.
Store code samples in ex/ and reference them directly.
#### region
The `region` shell script is a command intended to be used with `mdox-exec`.
```plain mdox-exec='region' mdox-expect-exit-code='1'
USAGE: region FILE REGION1 REGION2 ...
Extracts text from FILE marked by "// region" blocks.
```
For example, given the file:
```
foo
// region myregion
bar
// endregion myregion
baz
```
Running `region $FILE myregion` will print:
```
bar
```
The same region name may be used multiple times
to pull different snippets from the same file.
For example, given the file:
```go
// region provide-foo
func main() {
fx.New(
fx.Provide(
NewFoo,
// endregion provide-foo
NewBar,
// region provide-foo
),
).Run()
}
// endregion provide-foo
```
`region $FILE provide-foo` will print,
```go
func main() {
fx.New(
fx.Provide(
NewFoo,
),
).Run()
}
```

19
vendor/go.uber.org/fx/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2016-2018 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

86
vendor/go.uber.org/fx/Makefile generated vendored Normal file
View File

@@ -0,0 +1,86 @@
export GOBIN ?= $(shell pwd)/bin
GOLINT = $(GOBIN)/golint
STATICCHECK = $(GOBIN)/staticcheck
FXLINT = $(GOBIN)/fxlint
MDOX = $(GOBIN)/mdox
GO_FILES = $(shell \
find . '(' -path '*/.*' -o -path './vendor' -o -path '*/testdata/*' ')' -prune \
-o -name '*.go' -print | cut -b3-)
MODULES = . ./tools ./docs ./internal/e2e
# 'make cover' should not run on docs by default.
# We run that separately explicitly on a specific platform.
COVER_MODULES ?= $(filter-out ./docs,$(MODULES))
.PHONY: build
build:
go build ./...
.PHONY: install
install:
go mod download
.PHONY: test
test:
@$(foreach dir,$(MODULES),(cd $(dir) && go test -race ./...) &&) true
.PHONY: cover
cover:
@$(foreach dir,$(COVER_MODULES), \
(cd $(dir) && \
echo "[cover] $(dir)" && \
go test -race -coverprofile=cover.out -coverpkg=./... ./... && \
go tool cover -html=cover.out -o cover.html) &&) true
$(GOLINT): tools/go.mod
cd tools && go install golang.org/x/lint/golint
$(STATICCHECK): tools/go.mod
cd tools && go install honnef.co/go/tools/cmd/staticcheck
$(MDOX): tools/go.mod
cd tools && go install github.com/bwplotka/mdox
$(FXLINT): tools/cmd/fxlint/main.go
cd tools && go install go.uber.org/fx/tools/cmd/fxlint
.PHONY: lint
lint: $(GOLINT) $(STATICCHECK) $(FXLINT) docs-check
@rm -rf lint.log
@echo "Checking formatting..."
@gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log
@echo "Checking vet..."
@$(foreach dir,$(MODULES),(cd $(dir) && go vet ./... 2>&1) &&) true | tee -a lint.log
@echo "Checking lint..."
@$(foreach dir,$(MODULES),(cd $(dir) && $(GOLINT) ./... 2>&1) &&) true | tee -a lint.log
@echo "Checking staticcheck..."
@$(foreach dir,$(MODULES),(cd $(dir) && $(STATICCHECK) ./... 2>&1) &&) true | tee -a lint.log
@echo "Checking fxlint..."
@$(FXLINT) ./... | tee -a lint.log
@echo "Checking for unresolved FIXMEs..."
@git grep -i fixme | grep -v -e vendor -e Makefile -e .md | tee -a lint.log
@echo "Checking for license headers..."
@./checklicense.sh | tee -a lint.log
@[ ! -s lint.log ]
@echo "Checking 'go mod tidy'..."
@make tidy
@if ! git diff --quiet; then \
echo "'go mod tidy' resulted in changes or working tree is dirty:"; \
git --no-pager diff; \
fi
.PHONY: docs
docs:
cd docs && yarn build
.PHONY: docs-check
docs-check: $(MDOX)
@echo "Checking documentation"
@make -C docs check | tee -a lint.log
.PHONY: tidy
tidy:
@$(foreach dir,$(MODULES),(cd $(dir) && go mod tidy) &&) true

40
vendor/go.uber.org/fx/README.md generated vendored Normal file
View File

@@ -0,0 +1,40 @@
# :unicorn: Fx [![GoDoc](https://pkg.go.dev/badge/go.uber.org/fx)](https://pkg.go.dev/go.uber.org/fx) [![Github release](https://img.shields.io/github/release/uber-go/fx.svg)](https://github.com/uber-go/fx/releases) [![Build Status](https://github.com/uber-go/fx/actions/workflows/go.yml/badge.svg)](https://github.com/uber-go/fx/actions/workflows/go.yml) [![Coverage Status](https://codecov.io/gh/uber-go/fx/branch/master/graph/badge.svg)](https://codecov.io/gh/uber-go/fx/branch/master) [![Go Report Card](https://goreportcard.com/badge/go.uber.org/fx)](https://goreportcard.com/report/go.uber.org/fx)
Fx is a dependency injection system for Go.
**Benefits**
- Eliminate globals: Fx helps you remove global state from your application.
No more `init()` or global variables. Use Fx-managed singletons.
- Code reuse: Fx lets teams within your organization build loosely-coupled
and well-integrated shareable components.
- Battle tested: Fx is the backbone of nearly all Go services at Uber.
See our [docs](https://uber-go.github.io/fx/) to get started and/or
learn more about Fx.
## Installation
Use Go modules to install Fx in your application.
```shell
go get go.uber.org/fx@v1
```
## Getting started
To get started with Fx, [start here](https://uber-go.github.io/fx/get-started/).
## Stability
This library is `v1` and follows [SemVer](https://semver.org/) strictly.
No breaking changes will be made to exported APIs before `v2.0.0`.
This project follows the [Go Release Policy](https://golang.org/doc/devel/release.html#policy). Each major
version of Go is supported until there are two newer major releases.
## Stargazers over time
[![Stargazers over time](https://starchart.cc/uber-go/fx.svg)](https://starchart.cc/uber-go/fx)

1760
vendor/go.uber.org/fx/annotated.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

812
vendor/go.uber.org/fx/app.go generated vendored Normal file
View File

@@ -0,0 +1,812 @@
// Copyright (c) 2020-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"reflect"
"strings"
"time"
"go.uber.org/dig"
"go.uber.org/fx/fxevent"
"go.uber.org/fx/internal/fxclock"
"go.uber.org/fx/internal/fxlog"
"go.uber.org/fx/internal/fxreflect"
"go.uber.org/fx/internal/lifecycle"
"go.uber.org/multierr"
)
// DefaultTimeout is the default timeout for starting or stopping an
// application. It can be configured with the StartTimeout and StopTimeout
// options.
const DefaultTimeout = 15 * time.Second
// An Option configures an App using the functional options paradigm
// popularized by Rob Pike. If you're unfamiliar with this style, see
// https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html.
type Option interface {
fmt.Stringer
apply(*module)
}
// Error registers any number of errors with the application to short-circuit
// startup. If more than one error is given, the errors are combined into a
// single error.
//
// Similar to invocations, errors are applied in order. All Provide and Invoke
// options registered before or after an Error option will not be applied.
func Error(errs ...error) Option {
return errorOption(errs)
}
type errorOption []error
func (errs errorOption) apply(mod *module) {
mod.app.err = multierr.Append(mod.app.err, multierr.Combine(errs...))
}
func (errs errorOption) String() string {
return fmt.Sprintf("fx.Error(%v)", multierr.Combine(errs...))
}
// Options converts a collection of Options into a single Option. This allows
// packages to bundle sophisticated functionality into easy-to-use Fx modules.
// For example, a logging package might export a simple option like this:
//
// package logging
//
// var Module = fx.Provide(func() *log.Logger {
// return log.New(os.Stdout, "", 0)
// })
//
// A shared all-in-one microservice package could then use Options to bundle
// logging with similar metrics, tracing, and gRPC modules:
//
// package server
//
// var Module = fx.Options(
// logging.Module,
// metrics.Module,
// tracing.Module,
// grpc.Module,
// )
//
// Since this all-in-one module has a minimal API surface, it's easy to add
// new functionality to it without breaking existing users. Individual
// applications can take advantage of all this functionality with only one
// line of code:
//
// app := fx.New(server.Module)
//
// Use this pattern sparingly, since it limits the user's ability to customize
// their application.
func Options(opts ...Option) Option {
return optionGroup(opts)
}
type optionGroup []Option
func (og optionGroup) apply(mod *module) {
for _, opt := range og {
opt.apply(mod)
}
}
func (og optionGroup) String() string {
items := make([]string, len(og))
for i, opt := range og {
items[i] = fmt.Sprint(opt)
}
return fmt.Sprintf("fx.Options(%s)", strings.Join(items, ", "))
}
// StartTimeout changes the application's start timeout.
func StartTimeout(v time.Duration) Option {
return startTimeoutOption(v)
}
type startTimeoutOption time.Duration
func (t startTimeoutOption) apply(m *module) {
if m.parent != nil {
m.app.err = fmt.Errorf("fx.StartTimeout Option should be passed to top-level App, " +
"not to fx.Module")
} else {
m.app.startTimeout = time.Duration(t)
}
}
func (t startTimeoutOption) String() string {
return fmt.Sprintf("fx.StartTimeout(%v)", time.Duration(t))
}
// StopTimeout changes the application's stop timeout.
func StopTimeout(v time.Duration) Option {
return stopTimeoutOption(v)
}
type stopTimeoutOption time.Duration
func (t stopTimeoutOption) apply(m *module) {
if m.parent != nil {
m.app.err = fmt.Errorf("fx.StopTimeout Option should be passed to top-level App, " +
"not to fx.Module")
} else {
m.app.stopTimeout = time.Duration(t)
}
}
func (t stopTimeoutOption) String() string {
return fmt.Sprintf("fx.StopTimeout(%v)", time.Duration(t))
}
// RecoverFromPanics causes panics that occur in functions given to [Provide],
// [Decorate], and [Invoke] to be recovered from.
// This error can be retrieved as any other error, by using (*App).Err().
func RecoverFromPanics() Option {
return recoverFromPanicsOption{}
}
type recoverFromPanicsOption struct{}
func (o recoverFromPanicsOption) apply(m *module) {
if m.parent != nil {
m.app.err = fmt.Errorf("fx.RecoverFromPanics Option should be passed to top-level " +
"App, not to fx.Module")
} else {
m.app.recoverFromPanics = true
}
}
func (o recoverFromPanicsOption) String() string {
return "fx.RecoverFromPanics()"
}
// WithLogger specifies how Fx should build an fxevent.Logger to log its events
// to. The argument must be a constructor with one of the following return
// types.
//
// fxevent.Logger
// (fxevent.Logger, error)
//
// For example,
//
// WithLogger(func(logger *zap.Logger) fxevent.Logger {
// return &fxevent.ZapLogger{Logger: logger}
// })
func WithLogger(constructor interface{}) Option {
return withLoggerOption{
constructor: constructor,
Stack: fxreflect.CallerStack(1, 0),
}
}
type withLoggerOption struct {
constructor interface{}
Stack fxreflect.Stack
}
func (l withLoggerOption) apply(m *module) {
m.logConstructor = &provide{
Target: l.constructor,
Stack: l.Stack,
}
}
func (l withLoggerOption) String() string {
return fmt.Sprintf("fx.WithLogger(%s)", fxreflect.FuncName(l.constructor))
}
// Printer is the interface required by Fx's logging backend. It's implemented
// by most loggers, including the one bundled with the standard library.
//
// Note, this will be deprecate with next release and you will need to implement
// fxevent.Logger interface instead.
type Printer interface {
Printf(string, ...interface{})
}
// Logger redirects the application's log output to the provided printer.
// Deprecated: use WithLogger instead.
func Logger(p Printer) Option {
return loggerOption{p}
}
type loggerOption struct{ p Printer }
func (l loggerOption) apply(m *module) {
if m.parent != nil {
m.app.err = fmt.Errorf("fx.Logger Option should be passed to top-level App, " +
"not to fx.Module")
} else {
np := writerFromPrinter(l.p)
m.log = fxlog.DefaultLogger(np) // assuming np is thread-safe.
}
}
func (l loggerOption) String() string {
return fmt.Sprintf("fx.Logger(%v)", l.p)
}
// NopLogger disables the application's log output. Note that this makes some
// failures difficult to debug, since no errors are printed to console.
var NopLogger = WithLogger(func() fxevent.Logger { return fxevent.NopLogger })
// An App is a modular application built around dependency injection. Most
// users will only need to use the New constructor and the all-in-one Run
// convenience method. In more unusual cases, users may need to use the Err,
// Start, Done, and Stop methods by hand instead of relying on Run.
//
// New creates and initializes an App. All applications begin with a
// constructor for the Lifecycle type already registered.
//
// In addition to that built-in functionality, users typically pass a handful
// of Provide options and one or more Invoke options. The Provide options
// teach the application how to instantiate a variety of types, and the Invoke
// options describe how to initialize the application.
//
// When created, the application immediately executes all the functions passed
// via Invoke options. To supply these functions with the parameters they
// need, the application looks for constructors that return the appropriate
// types; if constructors for any required types are missing or any
// invocations return an error, the application will fail to start (and Err
// will return a descriptive error message).
//
// Once all the invocations (and any required constructors) have been called,
// New returns and the application is ready to be started using Run or Start.
// On startup, it executes any OnStart hooks registered with its Lifecycle.
// OnStart hooks are executed one at a time, in order, and must all complete
// within a configurable deadline (by default, 15 seconds). For details on the
// order in which OnStart hooks are executed, see the documentation for the
// Start method.
//
// At this point, the application has successfully started up. If started via
// Run, it will continue operating until it receives a shutdown signal from
// Done (see the Done documentation for details); if started explicitly via
// Start, it will operate until the user calls Stop. On shutdown, OnStop hooks
// execute one at a time, in reverse order, and must all complete within a
// configurable deadline (again, 15 seconds by default).
type App struct {
err error
clock fxclock.Clock
lifecycle *lifecycleWrapper
container *dig.Container
root *module
modules []*module
// Timeouts used
startTimeout time.Duration
stopTimeout time.Duration
// Decides how we react to errors when building the graph.
errorHooks []ErrorHandler
validate bool
// Whether to recover from panics in Dig container
recoverFromPanics bool
// Used to signal shutdowns.
receivers signalReceivers
osExit func(code int) // os.Exit override; used for testing only
}
// provide is a single constructor provided to Fx.
type provide struct {
// Constructor provided to Fx. This may be an fx.Annotated.
Target interface{}
// Stack trace of where this provide was made.
Stack fxreflect.Stack
// IsSupply is true when the Target constructor was emitted by fx.Supply.
IsSupply bool
SupplyType reflect.Type // set only if IsSupply
// Set if the type should be provided at private scope.
Private bool
}
// invoke is a single invocation request to Fx.
type invoke struct {
// Function to invoke.
Target interface{}
// Stack trace of where this invoke was made.
Stack fxreflect.Stack
}
// ErrorHandler handles Fx application startup errors.
type ErrorHandler interface {
HandleError(error)
}
// ErrorHook registers error handlers that implement error handling functions.
// They are executed on invoke failures. Passing multiple ErrorHandlers appends
// the new handlers to the application's existing list.
func ErrorHook(funcs ...ErrorHandler) Option {
return errorHookOption(funcs)
}
type errorHookOption []ErrorHandler
func (eho errorHookOption) apply(m *module) {
m.app.errorHooks = append(m.app.errorHooks, eho...)
}
func (eho errorHookOption) String() string {
items := make([]string, len(eho))
for i, eh := range eho {
items[i] = fmt.Sprint(eh)
}
return fmt.Sprintf("fx.ErrorHook(%v)", strings.Join(items, ", "))
}
type errorHandlerList []ErrorHandler
func (ehl errorHandlerList) HandleError(err error) {
for _, eh := range ehl {
eh.HandleError(err)
}
}
// validate sets *App into validation mode without running invoked functions.
func validate(validate bool) Option {
return &validateOption{
validate: validate,
}
}
type validateOption struct {
validate bool
}
func (o validateOption) apply(m *module) {
if m.parent != nil {
m.app.err = fmt.Errorf("fx.validate Option should be passed to top-level App, " +
"not to fx.Module")
} else {
m.app.validate = o.validate
}
}
func (o validateOption) String() string {
return fmt.Sprintf("fx.validate(%v)", o.validate)
}
// ValidateApp validates that supplied graph would run and is not missing any dependencies. This
// method does not invoke actual input functions.
func ValidateApp(opts ...Option) error {
opts = append(opts, validate(true))
app := New(opts...)
return app.Err()
}
// New creates and initializes an App, immediately executing any functions
// registered via Invoke options. See the documentation of the App struct for
// details on the application's initialization, startup, and shutdown logic.
func New(opts ...Option) *App {
logger := fxlog.DefaultLogger(os.Stderr)
app := &App{
clock: fxclock.System,
startTimeout: DefaultTimeout,
stopTimeout: DefaultTimeout,
receivers: newSignalReceivers(),
}
app.root = &module{
app: app,
// We start with a logger that writes to stderr. One of the
// following three things can change this:
//
// - fx.Logger was provided to change the output stream
// - fx.WithLogger was provided to change the logger
// implementation
// - Both, fx.Logger and fx.WithLogger were provided
//
// The first two cases are straightforward: we use what the
// user gave us. For the last case, however, we need to fall
// back to what was provided to fx.Logger if fx.WithLogger
// fails.
log: logger,
trace: []string{fxreflect.CallerStack(1, 2)[0].String()},
}
app.modules = append(app.modules, app.root)
for _, opt := range opts {
opt.apply(app.root)
}
// There are a few levels of wrapping on the lifecycle here. To quickly
// cover them:
//
// - lifecycleWrapper ensures that we don't unintentionally expose the
// Start and Stop methods of the internal lifecycle.Lifecycle type
// - lifecycleWrapper also adapts the internal lifecycle.Hook type into
// the public fx.Hook type.
// - appLogger ensures that the lifecycle always logs events to the
// "current" logger associated with the fx.App.
app.lifecycle = &lifecycleWrapper{
lifecycle.New(appLogger{app}, app.clock),
}
containerOptions := []dig.Option{
dig.DeferAcyclicVerification(),
dig.DryRun(app.validate),
}
if app.recoverFromPanics {
containerOptions = append(containerOptions, dig.RecoverFromPanics())
}
app.container = dig.New(containerOptions...)
for _, m := range app.modules {
m.build(app, app.container)
}
for _, m := range app.modules {
m.provideAll()
}
frames := fxreflect.CallerStack(0, 0) // include New in the stack for default Provides
app.root.provide(provide{
Target: func() Lifecycle { return app.lifecycle },
Stack: frames,
})
app.root.provide(provide{Target: app.shutdowner, Stack: frames})
app.root.provide(provide{Target: app.dotGraph, Stack: frames})
// Run decorators before executing any Invokes -- including the one
// inside constructCustomLogger.
app.err = multierr.Append(app.err, app.root.decorateAll())
// If you are thinking about returning here after provides: do not (just yet)!
// If a custom logger was being used, we're still buffering messages.
// We'll want to flush them to the logger.
// custom app logger will be initialized by the root module.
for _, m := range app.modules {
m.constructAllCustomLoggers()
}
// This error might have come from the provide loop above. We've
// already flushed to the custom logger, so we can return.
if app.err != nil {
return app
}
if err := app.root.executeInvokes(); err != nil {
app.err = err
if dig.CanVisualizeError(err) {
var b bytes.Buffer
dig.Visualize(app.container, &b, dig.VisualizeError(err))
err = errorWithGraph{
graph: b.String(),
err: err,
}
}
errorHandlerList(app.errorHooks).HandleError(err)
}
return app
}
func (app *App) log() fxevent.Logger {
return app.root.log
}
// DotGraph contains a DOT language visualization of the dependency graph in
// an Fx application. It is provided in the container by default at
// initialization. On failure to build the dependency graph, it is attached
// to the error and if possible, colorized to highlight the root cause of the
// failure.
type DotGraph string
type errWithGraph interface {
Graph() DotGraph
}
type errorWithGraph struct {
graph string
err error
}
func (err errorWithGraph) Graph() DotGraph {
return DotGraph(err.graph)
}
func (err errorWithGraph) Error() string {
return err.err.Error()
}
// VisualizeError returns the visualization of the error if available.
func VisualizeError(err error) (string, error) {
if e, ok := err.(errWithGraph); ok && e.Graph() != "" {
return string(e.Graph()), nil
}
return "", errors.New("unable to visualize error")
}
// Exits the application with the given exit code.
func (app *App) exit(code int) {
osExit := os.Exit
if app.osExit != nil {
osExit = app.osExit
}
osExit(code)
}
// Run starts the application, blocks on the signals channel, and then
// gracefully shuts the application down. It uses DefaultTimeout to set a
// deadline for application startup and shutdown, unless the user has
// configured different timeouts with the StartTimeout or StopTimeout options.
// It's designed to make typical applications simple to run.
//
// However, all of Run's functionality is implemented in terms of the exported
// Start, Done, and Stop methods. Applications with more specialized needs
// can use those methods directly instead of relying on Run.
func (app *App) Run() {
// Historically, we do not os.Exit(0) even though most applications
// cede control to Fx with they call app.Run. To avoid a breaking
// change, never os.Exit for success.
if code := app.run(app.Wait); code != 0 {
app.exit(code)
}
}
func (app *App) run(done func() <-chan ShutdownSignal) (exitCode int) {
startCtx, cancel := app.clock.WithTimeout(context.Background(), app.StartTimeout())
defer cancel()
if err := app.Start(startCtx); err != nil {
return 1
}
sig := <-done()
app.log().LogEvent(&fxevent.Stopping{Signal: sig.Signal})
exitCode = sig.ExitCode
stopCtx, cancel := app.clock.WithTimeout(context.Background(), app.StopTimeout())
defer cancel()
if err := app.Stop(stopCtx); err != nil {
return 1
}
return exitCode
}
// Err returns any error encountered during New's initialization. See the
// documentation of the New method for details, but typical errors include
// missing constructors, circular dependencies, constructor errors, and
// invocation errors.
//
// Most users won't need to use this method, since both Run and Start
// short-circuit if initialization failed.
func (app *App) Err() error {
return app.err
}
var (
_onStartHook = "OnStart"
_onStopHook = "OnStop"
)
// Start kicks off all long-running goroutines, like network servers or
// message queue consumers. It does this by interacting with the application's
// Lifecycle.
//
// By taking a dependency on the Lifecycle type, some of the user-supplied
// functions called during initialization may have registered start and stop
// hooks. Because initialization calls constructors serially and in dependency
// order, hooks are naturally registered in serial and dependency order too.
//
// Start executes all OnStart hooks registered with the application's
// Lifecycle, one at a time and in order. This ensures that each constructor's
// start hooks aren't executed until all its dependencies' start hooks
// complete. If any of the start hooks return an error, Start short-circuits,
// calls Stop, and returns the inciting error.
//
// Note that Start short-circuits immediately if the New constructor
// encountered any errors in application initialization.
func (app *App) Start(ctx context.Context) (err error) {
defer func() {
app.log().LogEvent(&fxevent.Started{Err: err})
}()
if app.err != nil {
// Some provides failed, short-circuit immediately.
return app.err
}
return withTimeout(ctx, &withTimeoutParams{
hook: _onStartHook,
callback: app.start,
lifecycle: app.lifecycle,
log: app.log(),
})
}
// withRollback will execute an anonymous function with a given context.
// if the anon func returns an error, rollback methods will be called and related events emitted
func (app *App) withRollback(
ctx context.Context,
f func(context.Context) error,
) error {
if err := f(ctx); err != nil {
app.log().LogEvent(&fxevent.RollingBack{StartErr: err})
stopErr := app.lifecycle.Stop(ctx)
app.log().LogEvent(&fxevent.RolledBack{Err: stopErr})
if stopErr != nil {
return multierr.Append(err, stopErr)
}
return err
}
return nil
}
func (app *App) start(ctx context.Context) error {
return app.withRollback(ctx, func(ctx context.Context) error {
if err := app.lifecycle.Start(ctx); err != nil {
return err
}
app.receivers.Start(ctx)
return nil
})
}
// Stop gracefully stops the application. It executes any registered OnStop
// hooks in reverse order, so that each constructor's stop hooks are called
// before its dependencies' stop hooks.
//
// If the application didn't start cleanly, only hooks whose OnStart phase was
// called are executed. However, all those hooks are executed, even if some
// fail.
func (app *App) Stop(ctx context.Context) (err error) {
defer func() {
app.log().LogEvent(&fxevent.Stopped{Err: err})
}()
cb := func(ctx context.Context) error {
defer app.receivers.Stop(ctx)
return app.lifecycle.Stop(ctx)
}
return withTimeout(ctx, &withTimeoutParams{
hook: _onStopHook,
callback: cb,
lifecycle: app.lifecycle,
log: app.log(),
})
}
// Done returns a channel of signals to block on after starting the
// application. Applications listen for the SIGINT and SIGTERM signals; during
// development, users can send the application SIGTERM by pressing Ctrl-C in
// the same terminal as the running process.
//
// Alternatively, a signal can be broadcast to all done channels manually by
// using the Shutdown functionality (see the Shutdowner documentation for details).
//
// Note: The channel Done returns will not receive a signal unless the application
// as been started via Start or Run.
func (app *App) Done() <-chan os.Signal {
return app.receivers.Done()
}
// Wait returns a channel of [ShutdownSignal] to block on after starting the
// application and function, similar to [App.Done], but with a minor difference.
// Should an ExitCode be provided as a [ShutdownOption] to
// the Shutdowner Shutdown method, the exit code will be available as part
// of the ShutdownSignal struct.
//
// Should the app receive a SIGTERM or SIGINT, the given
// signal will be populated in the ShutdownSignal struct.
func (app *App) Wait() <-chan ShutdownSignal {
return app.receivers.Wait()
}
// StartTimeout returns the configured startup timeout. Apps default to using
// DefaultTimeout, but users can configure this behavior using the
// StartTimeout option.
func (app *App) StartTimeout() time.Duration {
return app.startTimeout
}
// StopTimeout returns the configured shutdown timeout. Apps default to using
// DefaultTimeout, but users can configure this behavior using the StopTimeout
// option.
func (app *App) StopTimeout() time.Duration {
return app.stopTimeout
}
func (app *App) dotGraph() (DotGraph, error) {
var b bytes.Buffer
err := dig.Visualize(app.container, &b)
return DotGraph(b.String()), err
}
type withTimeoutParams struct {
log fxevent.Logger
hook string
callback func(context.Context) error
lifecycle *lifecycleWrapper
}
// errHookCallbackExited is returned when a hook callback does not finish executing
var errHookCallbackExited = errors.New("goroutine exited without returning")
func withTimeout(ctx context.Context, param *withTimeoutParams) error {
c := make(chan error, 1)
go func() {
// If runtime.Goexit() is called from within the callback
// then nothing is written to the chan.
// However the defer will still be called, so we can write to the chan,
// to avoid hanging until the timeout is reached.
callbackExited := false
defer func() {
if !callbackExited {
c <- errHookCallbackExited
}
}()
c <- param.callback(ctx)
callbackExited = true
}()
var err error
select {
case <-ctx.Done():
err = ctx.Err()
case err = <-c:
// If the context finished at the same time as the callback
// prefer the context error.
// This eliminates non-determinism in select-case selection.
if ctx.Err() != nil {
err = ctx.Err()
}
}
return err
}
// appLogger logs events to the given Fx app's "current" logger.
//
// Use this with lifecycle, for example, to ensure that events always go to the
// correct logger.
type appLogger struct{ app *App }
func (l appLogger) LogEvent(ev fxevent.Event) {
l.app.log().LogEvent(ev)
}

29
vendor/go.uber.org/fx/app_unixes.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package fx
import "golang.org/x/sys/unix"
const _sigINT = unix.SIGINT
const _sigTERM = unix.SIGTERM

29
vendor/go.uber.org/fx/app_wasm.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build (js && wasm) || (wasip1 && wasm)
// +build js,wasm wasip1,wasm
package fx
import "syscall"
const _sigINT = syscall.SIGINT
const _sigTERM = syscall.SIGTERM

29
vendor/go.uber.org/fx/app_windows.go generated vendored Normal file
View File

@@ -0,0 +1,29 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build windows
// +build windows
package fx
import "golang.org/x/sys/windows"
const _sigINT = windows.SIGINT
const _sigTERM = windows.SIGTERM

17
vendor/go.uber.org/fx/checklicense.sh generated vendored Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/bash -e
ERROR_COUNT=0
while read -r file
do
case "$(head -1 "${file}")" in
*"Copyright (c) "*" Uber Technologies, Inc.")
# everything's cool
;;
*)
echo "$file is missing license header."
(( ERROR_COUNT++ ))
;;
esac
done < <(git ls-files "*\.go" | grep -v /testdata/)
exit $ERROR_COUNT

232
vendor/go.uber.org/fx/decorate.go generated vendored Normal file
View File

@@ -0,0 +1,232 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"reflect"
"strings"
"go.uber.org/dig"
"go.uber.org/fx/internal/fxreflect"
)
// Decorate specifies one or more decorator functions to an Fx application.
//
// # Decorator functions
//
// Decorator functions let users augment objects in the graph.
// They can take in zero or more dependencies that must be provided to the
// application with fx.Provide, and produce one or more values that can be used
// by other fx.Provide and fx.Invoke calls.
//
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// })
// fx.Invoke(func(log *zap.Logger) {
// log.Info("hello")
// // Output:
// // {"level": "info","logger":"myapp","msg":"hello"}
// })
//
// The following decorator accepts multiple dependencies from the graph,
// augments and returns one of them.
//
// fx.Decorate(func(log *zap.Logger, cfg *Config) *zap.Logger {
// return log.Named(cfg.Name)
// })
//
// Similar to fx.Provide, functions passed to fx.Decorate may optionally return
// an error as their last result.
// If a decorator returns a non-nil error, it will halt application startup.
//
// fx.Decorate(func(conn *sql.DB, cfg *Config) (*sql.DB, error) {
// if err := conn.Ping(); err != nil {
// return sql.Open("driver-name", cfg.FallbackDB)
// }
// return conn, nil
// })
//
// Decorators support both, fx.In and fx.Out structs, similar to fx.Provide and
// fx.Invoke.
//
// type Params struct {
// fx.In
//
// Client usersvc.Client `name:"readOnly"`
// }
//
// type Result struct {
// fx.Out
//
// Client usersvc.Client `name:"readOnly"`
// }
//
// fx.Decorate(func(p Params) Result {
// ...
// })
//
// Decorators can be annotated with the fx.Annotate function, but not with the
// fx.Annotated type. Refer to documentation on fx.Annotate() to learn how to
// use it for annotating functions.
//
// fx.Decorate(
// fx.Annotate(
// func(client usersvc.Client) usersvc.Client {
// // ...
// },
// fx.ParamTags(`name:"readOnly"`),
// fx.ResultTags(`name:"readOnly"`),
// ),
// )
//
// Decorators support augmenting, filtering, or replacing value groups.
// To decorate a value group, expect the entire value group slice and produce
// the new slice.
//
// type HandlerParam struct {
// fx.In
//
// Log *zap.Logger
// Handlers []Handler `group:"server"
// }
//
// type HandlerResult struct {
// fx.Out
//
// Handlers []Handler `group:"server"
// }
//
// fx.Decorate(func(p HandlerParam) HandlerResult {
// var r HandlerResult
// for _, handler := range p.Handlers {
// r.Handlers = append(r.Handlers, wrapWithLogger(p.Log, handler))
// }
// return r
// }),
//
// # Decorator scope
//
// Modifications made to the Fx graph with fx.Decorate are scoped to the
// deepest fx.Module inside which the decorator was specified.
//
// fx.Module("mymodule",
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// }),
// fx.Invoke(func(log *zap.Logger) {
// log.Info("decorated logger")
// // Output:
// // {"level": "info","logger":"myapp","msg":"decorated logger"}
// }),
// ),
// fx.Invoke(func(log *zap.Logger) {
// log.Info("plain logger")
// // Output:
// // {"level": "info","msg":"plain logger"}
// }),
//
// Decorations specified in the top-level fx.New call apply across the
// application and chain with module-specific decorators.
//
// fx.New(
// // ...
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.With(zap.Field("service", "myservice"))
// }),
// // ...
// fx.Invoke(func(log *zap.Logger) {
// log.Info("outer decorator")
// // Output:
// // {"level": "info","service":"myservice","msg":"outer decorator"}
// }),
// // ...
// fx.Module("mymodule",
// fx.Decorate(func(log *zap.Logger) *zap.Logger {
// return log.Named("myapp")
// }),
// fx.Invoke(func(log *zap.Logger) {
// log.Info("inner decorator")
// // Output:
// // {"level": "info","logger":"myapp","service":"myservice","msg":"inner decorator"}
// }),
// ),
// )
func Decorate(decorators ...interface{}) Option {
return decorateOption{
Targets: decorators,
Stack: fxreflect.CallerStack(1, 0),
}
}
type decorateOption struct {
Targets []interface{}
Stack fxreflect.Stack
}
func (o decorateOption) apply(mod *module) {
for _, target := range o.Targets {
mod.decorators = append(mod.decorators, decorator{
Target: target,
Stack: o.Stack,
})
}
}
func (o decorateOption) String() string {
items := make([]string, len(o.Targets))
for i, f := range o.Targets {
items[i] = fxreflect.FuncName(f)
}
return fmt.Sprintf("fx.Decorate(%s)", strings.Join(items, ", "))
}
// decorator is a single decorator used in Fx.
type decorator struct {
// Decorator provided to Fx.
Target interface{}
// Stack trace of where this provide was made.
Stack fxreflect.Stack
// Whether this decorator was specified via fx.Replace
IsReplace bool
ReplaceType reflect.Type // set only if IsReplace
}
func runDecorator(c container, d decorator, opts ...dig.DecorateOption) (err error) {
decorator := d.Target
defer func() {
if err != nil {
err = fmt.Errorf("fx.Decorate(%v) from:\n%+vFailed: %v", decorator, d.Stack, err)
}
}()
switch decorator := decorator.(type) {
case annotated:
if dcor, derr := decorator.Build(); derr == nil {
err = c.Decorate(dcor, opts...)
}
default:
err = c.Decorate(decorator, opts...)
}
return
}

39
vendor/go.uber.org/fx/doc.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package fx is a framework that makes it easy to build applications out of
// reusable, composable modules.
//
// Fx applications use dependency injection to eliminate globals without the
// tedium of manually wiring together function calls. Unlike other approaches
// to dependency injection, Fx works with plain Go functions: you don't need
// to use struct tags or embed special types, so Fx automatically works well
// with most Go packages.
//
// Basic usage is explained in the package-level example below. If you're new
// to Fx, start there! Advanced features, including named instances, optional
// parameters, and value groups, are explained under the In and Out types.
//
// # Testing Fx Applications
//
// To test functions that use the Lifecycle type or to write end-to-end tests
// of your Fx application, use the helper functions and types provided by the
// go.uber.org/fx/fxtest package.
package fx // import "go.uber.org/fx"

156
vendor/go.uber.org/fx/extract.go generated vendored Normal file
View File

@@ -0,0 +1,156 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"reflect"
"unicode"
"unicode/utf8"
)
var _typeOfIn = reflect.TypeOf(In{})
// Extract fills the given struct with values from the dependency injection
// container on application initialization. The target MUST be a pointer to a
// struct. Only exported fields will be filled.
//
// Deprecated: Use Populate instead.
func Extract(target interface{}) Option {
v := reflect.ValueOf(target)
if t := v.Type(); t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
return Error(fmt.Errorf("Extract expected a pointer to a struct, got a %v", t))
}
v = v.Elem()
t := v.Type()
// We generate a function which accepts a single fx.In struct as an
// argument. This struct contains all exported fields of the target
// struct.
// Fields of the generated fx.In struct.
fields := make([]reflect.StructField, 0, t.NumField()+1)
// Anonymous dig.In field.
fields = append(fields, reflect.StructField{
Name: _typeOfIn.Name(),
Anonymous: true,
Type: _typeOfIn,
})
// List of values in the target struct aligned with the fields of the
// generated struct.
//
// So for example, if the target is,
//
// var target struct {
// Foo io.Reader
// bar []byte
// Baz io.Writer
// }
//
// The generated struct has the shape,
//
// struct {
// fx.In
//
// F0 io.Reader
// F2 io.Writer
// }
//
// And `targets` is,
//
// [
// target.Field(0), // Foo io.Reader
// target.Field(2), // Baz io.Writer
// ]
//
// As we iterate through the fields of the generated struct, we can copy
// the value into the corresponding value in the targets list.
targets := make([]reflect.Value, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
// Skip unexported fields.
if f.Anonymous {
// If embedded, StructField.PkgPath is not a reliable indicator of
// whether the field is exported. See
// https://github.com/golang/go/issues/21122
t := f.Type
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if !isExported(t.Name()) {
continue
}
} else if f.PkgPath != "" {
continue
}
// We don't copy over names or embedded semantics.
fields = append(fields, reflect.StructField{
Name: fmt.Sprintf("F%d", i),
Type: f.Type,
Tag: f.Tag,
})
targets = append(targets, v.Field(i))
}
// Equivalent to,
//
// func(r struct {
// fx.In
//
// F1 Foo
// F2 Bar
// }) {
// target.Foo = r.F1
// target.Bar = r.F2
// }
fn := reflect.MakeFunc(
reflect.FuncOf(
[]reflect.Type{reflect.StructOf(fields)},
nil, /* results */
false, /* variadic */
),
func(args []reflect.Value) []reflect.Value {
result := args[0]
for i := 1; i < result.NumField(); i++ {
targets[i-1].Set(result.Field(i))
}
return nil
},
)
return Invoke(fn.Interface())
}
// isExported reports whether the identifier is exported.
func isExported(id string) bool {
r, _ := utf8.DecodeRuneInString(id)
return unicode.IsUpper(r)
}

152
vendor/go.uber.org/fx/fxevent/console.go generated vendored Normal file
View File

@@ -0,0 +1,152 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxevent
import (
"fmt"
"io"
"strings"
)
// ConsoleLogger is an Fx event logger that attempts to write human-readable
// messages to the console.
//
// Use this during development.
type ConsoleLogger struct {
W io.Writer
}
var _ Logger = (*ConsoleLogger)(nil)
func (l *ConsoleLogger) logf(msg string, args ...interface{}) {
fmt.Fprintf(l.W, "[Fx] "+msg+"\n", args...)
}
// LogEvent logs the given event to the provided Zap logger.
func (l *ConsoleLogger) LogEvent(event Event) {
switch e := event.(type) {
case *OnStartExecuting:
l.logf("HOOK OnStart\t\t%s executing (caller: %s)", e.FunctionName, e.CallerName)
case *OnStartExecuted:
if e.Err != nil {
l.logf("HOOK OnStart\t\t%s called by %s failed in %s: %+v", e.FunctionName, e.CallerName, e.Runtime, e.Err)
} else {
l.logf("HOOK OnStart\t\t%s called by %s ran successfully in %s", e.FunctionName, e.CallerName, e.Runtime)
}
case *OnStopExecuting:
l.logf("HOOK OnStop\t\t%s executing (caller: %s)", e.FunctionName, e.CallerName)
case *OnStopExecuted:
if e.Err != nil {
l.logf("HOOK OnStop\t\t%s called by %s failed in %s: %+v", e.FunctionName, e.CallerName, e.Runtime, e.Err)
} else {
l.logf("HOOK OnStop\t\t%s called by %s ran successfully in %s", e.FunctionName, e.CallerName, e.Runtime)
}
case *Supplied:
if e.Err != nil {
l.logf("ERROR\tFailed to supply %v: %+v", e.TypeName, e.Err)
} else if e.ModuleName != "" {
l.logf("SUPPLY\t%v from module %q", e.TypeName, e.ModuleName)
} else {
l.logf("SUPPLY\t%v", e.TypeName)
}
case *Provided:
var privateStr string
if e.Private {
privateStr = " (PRIVATE)"
}
for _, rtype := range e.OutputTypeNames {
if e.ModuleName != "" {
l.logf("PROVIDE%v\t%v <= %v from module %q", privateStr, rtype, e.ConstructorName, e.ModuleName)
} else {
l.logf("PROVIDE%v\t%v <= %v", privateStr, rtype, e.ConstructorName)
}
}
if e.Err != nil {
l.logf("Error after options were applied: %+v", e.Err)
}
case *Replaced:
for _, rtype := range e.OutputTypeNames {
if e.ModuleName != "" {
l.logf("REPLACE\t%v from module %q", rtype, e.ModuleName)
} else {
l.logf("REPLACE\t%v", rtype)
}
}
if e.Err != nil {
l.logf("ERROR\tFailed to replace: %+v", e.Err)
}
case *Decorated:
for _, rtype := range e.OutputTypeNames {
if e.ModuleName != "" {
l.logf("DECORATE\t%v <= %v from module %q", rtype, e.DecoratorName, e.ModuleName)
} else {
l.logf("DECORATE\t%v <= %v", rtype, e.DecoratorName)
}
}
if e.Err != nil {
l.logf("Error after options were applied: %+v", e.Err)
}
case *Run:
var moduleStr string
if e.ModuleName != "" {
moduleStr = fmt.Sprintf(" from module %q", e.ModuleName)
}
l.logf("RUN\t%v: %v%v", e.Kind, e.Name, moduleStr)
if e.Err != nil {
l.logf("Error returned: %+v", e.Err)
}
case *Invoking:
if e.ModuleName != "" {
l.logf("INVOKE\t\t%s from module %q", e.FunctionName, e.ModuleName)
} else {
l.logf("INVOKE\t\t%s", e.FunctionName)
}
case *Invoked:
if e.Err != nil {
l.logf("ERROR\t\tfx.Invoke(%v) called from:\n%+vFailed: %+v", e.FunctionName, e.Trace, e.Err)
}
case *Stopping:
l.logf("%v", strings.ToUpper(e.Signal.String()))
case *Stopped:
if e.Err != nil {
l.logf("ERROR\t\tFailed to stop cleanly: %+v", e.Err)
}
case *RollingBack:
l.logf("ERROR\t\tStart failed, rolling back: %+v", e.StartErr)
case *RolledBack:
if e.Err != nil {
l.logf("ERROR\t\tCouldn't roll back cleanly: %+v", e.Err)
}
case *Started:
if e.Err != nil {
l.logf("ERROR\t\tFailed to start: %+v", e.Err)
} else {
l.logf("RUNNING")
}
case *LoggerInitialized:
if e.Err != nil {
l.logf("ERROR\t\tFailed to initialize custom logger: %+v", e.Err)
} else {
l.logf("LOGGER\tInitialized custom logger from %v", e.ConstructorName)
}
}
}

282
vendor/go.uber.org/fx/fxevent/event.go generated vendored Normal file
View File

@@ -0,0 +1,282 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxevent
import (
"os"
"time"
)
// Event defines an event emitted by fx.
type Event interface {
event() // Only fxlog can implement this interface.
}
// Passing events by type to make Event hashable in the future.
func (*OnStartExecuting) event() {}
func (*OnStartExecuted) event() {}
func (*OnStopExecuting) event() {}
func (*OnStopExecuted) event() {}
func (*Supplied) event() {}
func (*Provided) event() {}
func (*Replaced) event() {}
func (*Decorated) event() {}
func (*Run) event() {}
func (*Invoking) event() {}
func (*Invoked) event() {}
func (*Stopping) event() {}
func (*Stopped) event() {}
func (*RollingBack) event() {}
func (*RolledBack) event() {}
func (*Started) event() {}
func (*LoggerInitialized) event() {}
// OnStartExecuting is emitted before an OnStart hook is executed.
type OnStartExecuting struct {
// FunctionName is the name of the function that will be executed.
FunctionName string
// CallerName is the name of the function that scheduled the hook for
// execution.
CallerName string
}
// OnStartExecuted is emitted after an OnStart hook has been executed.
type OnStartExecuted struct {
// FunctionName is the name of the function that was executed.
FunctionName string
// CallerName is the name of the function that scheduled the hook for
// execution.
CallerName string
// Method specifies the kind of the hook. This is one of "OnStart" and
// "OnStop".
Method string
// Runtime specifies how long it took to run this hook.
Runtime time.Duration
// Err is non-nil if the hook failed to execute.
Err error
}
// OnStopExecuting is emitted before an OnStop hook is executed.
type OnStopExecuting struct {
// FunctionName is the name of the function that will be executed.
FunctionName string
// CallerName is the name of the function that scheduled the hook for
// execution.
CallerName string
}
// OnStopExecuted is emitted after an OnStop hook has been executed.
type OnStopExecuted struct {
// FunctionName is the name of the function that was executed.
FunctionName string
// CallerName is the name of the function that scheduled the hook for
// execution.
CallerName string
// Runtime specifies how long it took to run this hook.
Runtime time.Duration
// Err is non-nil if the hook failed to execute.
Err error
}
// Supplied is emitted after a value is added with fx.Supply.
type Supplied struct {
// TypeName is the name of the type of value that was added.
TypeName string
// StackTrace is the stack trace of the call to Supply.
StackTrace []string
// ModuleTrace contains the module locations through which this value was added.
ModuleTrace []string
// ModuleName is the name of the module in which the value was added to.
ModuleName string
// Err is non-nil if we failed to supply the value.
Err error
}
// Provided is emitted when a constructor is provided to Fx.
type Provided struct {
// ConstructorName is the name of the constructor that was provided to
// Fx.
ConstructorName string
// StackTrace is the stack trace of where the constructor was provided to Fx.
StackTrace []string
// ModuleTrace contains the module locations through which this was provided to Fx.
ModuleTrace []string
// OutputTypeNames is a list of names of types that are produced by
// this constructor.
OutputTypeNames []string
// ModuleName is the name of the module in which the constructor was
// provided to.
ModuleName string
// Err is non-nil if we failed to provide this constructor.
Err error
// Private denotes whether the provided constructor is a [Private] constructor.
Private bool
}
// Replaced is emitted when a value replaces a type in Fx.
type Replaced struct {
// OutputTypeNames is a list of names of types that were replaced.
OutputTypeNames []string
// StackTrace is the stack trace of the call to Replace.
StackTrace []string
// ModuleTrace contains the module locations through which this value was added.
ModuleTrace []string
// ModuleName is the name of the module in which the value was added to.
ModuleName string
// Err is non-nil if we failed to supply the value.
Err error
}
// Decorated is emitted when a decorator is executed in Fx.
type Decorated struct {
// DecoratorName is the name of the decorator function that was
// provided to Fx.
DecoratorName string
// StackTrace is the stack trace of where the decorator was given to Fx.
StackTrace []string
// ModuleTrace contains the module locations through which this value was added.
ModuleTrace []string
// ModuleName is the name of the module in which the value was added to.
ModuleName string
// OutputTypeNames is a list of names of types that are decorated by
// this decorator.
OutputTypeNames []string
// Err is non-nil if we failed to run this decorator.
Err error
}
// Run is emitted after a constructor, decorator, or supply/replace stub is run by Fx.
type Run struct {
// Name is the name of the function that was run.
Name string
// Kind indicates which Fx option was used to pass along the function.
// It is either "provide", "decorate", "supply", or "replace".
Kind string
// ModuleName is the name of the module in which the function belongs.
ModuleName string
// Err is non-nil if the function returned an error.
// If fx.RecoverFromPanics is used, this will include panics.
Err error
}
// Invoking is emitted before we invoke a function specified with fx.Invoke.
type Invoking struct {
// FunctionName is the name of the function that will be invoked.
FunctionName string
// ModuleName is the name of the module in which the value was added to.
ModuleName string
}
// Invoked is emitted after we invoke a function specified with fx.Invoke,
// whether it succeeded or failed.
type Invoked struct {
// Functionname is the name of the function that was invoked.
FunctionName string
// ModuleName is the name of the module in which the value was added to.
ModuleName string
// Err is non-nil if the function failed to execute.
Err error
// Trace records information about where the fx.Invoke call was made.
// Note that this is NOT a stack trace of the error itself.
Trace string
}
// Started is emitted when an application is started successfully and/or it
// errored.
type Started struct {
// Err is non-nil if the application failed to start successfully.
Err error
}
// Stopping is emitted when the application receives a signal to shut down
// after starting. This may happen with fx.Shutdowner or by sending a signal to
// the application on the command line.
type Stopping struct {
// Signal is the signal that caused this shutdown.
Signal os.Signal
}
// Stopped is emitted when the application has finished shutting down, whether
// successfully or not.
type Stopped struct {
// Err is non-nil if errors were encountered during shutdown.
Err error
}
// RollingBack is emitted when the application failed to start up due to an
// error, and is being rolled back.
type RollingBack struct {
// StartErr is the error that caused this rollback.
StartErr error
}
// RolledBack is emitted after a service has been rolled back, whether it
// succeeded or not.
type RolledBack struct {
// Err is non-nil if the rollback failed.
Err error
}
// LoggerInitialized is emitted when a logger supplied with fx.WithLogger is
// instantiated, or if it fails to instantiate.
type LoggerInitialized struct {
// ConstructorName is the name of the constructor that builds this
// logger.
ConstructorName string
// Err is non-nil if the logger failed to build.
Err error
}

38
vendor/go.uber.org/fx/fxevent/logger.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxevent
// Logger defines interface used for logging.
type Logger interface {
// LogEvent is called when a logging event is emitted.
LogEvent(Event)
}
// NopLogger is an Fx event logger that ignores all messages.
var NopLogger = nopLogger{}
type nopLogger struct{}
var _ Logger = nopLogger{}
func (nopLogger) LogEvent(Event) {}
func (nopLogger) String() string { return "NopLogger" }

240
vendor/go.uber.org/fx/fxevent/zap.go generated vendored Normal file
View File

@@ -0,0 +1,240 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxevent
import (
"strings"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// ZapLogger is an Fx event logger that logs events to Zap.
type ZapLogger struct {
Logger *zap.Logger
logLevel zapcore.Level // default: zapcore.InfoLevel
errorLevel *zapcore.Level
}
var _ Logger = (*ZapLogger)(nil)
// UseErrorLevel sets the level of error logs emitted by Fx to level.
func (l *ZapLogger) UseErrorLevel(level zapcore.Level) {
l.errorLevel = &level
}
// UseLogLevel sets the level of non-error logs emitted by Fx to level.
func (l *ZapLogger) UseLogLevel(level zapcore.Level) {
l.logLevel = level
}
func (l *ZapLogger) logEvent(msg string, fields ...zap.Field) {
l.Logger.Log(l.logLevel, msg, fields...)
}
func (l *ZapLogger) logError(msg string, fields ...zap.Field) {
lvl := zapcore.ErrorLevel
if l.errorLevel != nil {
lvl = *l.errorLevel
}
l.Logger.Log(lvl, msg, fields...)
}
// LogEvent logs the given event to the provided Zap logger.
func (l *ZapLogger) LogEvent(event Event) {
switch e := event.(type) {
case *OnStartExecuting:
l.logEvent("OnStart hook executing",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
)
case *OnStartExecuted:
if e.Err != nil {
l.logError("OnStart hook failed",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.Error(e.Err),
)
} else {
l.logEvent("OnStart hook executed",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.String("runtime", e.Runtime.String()),
)
}
case *OnStopExecuting:
l.logEvent("OnStop hook executing",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
)
case *OnStopExecuted:
if e.Err != nil {
l.logError("OnStop hook failed",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.Error(e.Err),
)
} else {
l.logEvent("OnStop hook executed",
zap.String("callee", e.FunctionName),
zap.String("caller", e.CallerName),
zap.String("runtime", e.Runtime.String()),
)
}
case *Supplied:
if e.Err != nil {
l.logError("error encountered while applying options",
zap.String("type", e.TypeName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.Error(e.Err))
} else {
l.logEvent("supplied",
zap.String("type", e.TypeName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
)
}
case *Provided:
for _, rtype := range e.OutputTypeNames {
l.logEvent("provided",
zap.String("constructor", e.ConstructorName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.String("type", rtype),
maybeBool("private", e.Private),
)
}
if e.Err != nil {
l.logError("error encountered while applying options",
moduleField(e.ModuleName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
zap.Error(e.Err))
}
case *Replaced:
for _, rtype := range e.OutputTypeNames {
l.logEvent("replaced",
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.String("type", rtype),
)
}
if e.Err != nil {
l.logError("error encountered while replacing",
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.Error(e.Err))
}
case *Decorated:
for _, rtype := range e.OutputTypeNames {
l.logEvent("decorated",
zap.String("decorator", e.DecoratorName),
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.String("type", rtype),
)
}
if e.Err != nil {
l.logError("error encountered while applying options",
zap.Strings("stacktrace", e.StackTrace),
zap.Strings("moduletrace", e.ModuleTrace),
moduleField(e.ModuleName),
zap.Error(e.Err))
}
case *Run:
if e.Err != nil {
l.logError("error returned",
zap.String("name", e.Name),
zap.String("kind", e.Kind),
moduleField(e.ModuleName),
zap.Error(e.Err),
)
} else {
l.logEvent("run",
zap.String("name", e.Name),
zap.String("kind", e.Kind),
moduleField(e.ModuleName),
)
}
case *Invoking:
// Do not log stack as it will make logs hard to read.
l.logEvent("invoking",
zap.String("function", e.FunctionName),
moduleField(e.ModuleName),
)
case *Invoked:
if e.Err != nil {
l.logError("invoke failed",
zap.Error(e.Err),
zap.String("stack", e.Trace),
zap.String("function", e.FunctionName),
moduleField(e.ModuleName),
)
}
case *Stopping:
l.logEvent("received signal",
zap.String("signal", strings.ToUpper(e.Signal.String())))
case *Stopped:
if e.Err != nil {
l.logError("stop failed", zap.Error(e.Err))
}
case *RollingBack:
l.logError("start failed, rolling back", zap.Error(e.StartErr))
case *RolledBack:
if e.Err != nil {
l.logError("rollback failed", zap.Error(e.Err))
}
case *Started:
if e.Err != nil {
l.logError("start failed", zap.Error(e.Err))
} else {
l.logEvent("started")
}
case *LoggerInitialized:
if e.Err != nil {
l.logError("custom logger initialization failed", zap.Error(e.Err))
} else {
l.logEvent("initialized custom fxevent.Logger", zap.String("function", e.ConstructorName))
}
}
}
func moduleField(name string) zap.Field {
if len(name) == 0 {
return zap.Skip()
}
return zap.String("module", name)
}
func maybeBool(name string, b bool) zap.Field {
if b {
return zap.Bool(name, true)
}
return zap.Skip()
}

364
vendor/go.uber.org/fx/inout.go generated vendored Normal file
View File

@@ -0,0 +1,364 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import "go.uber.org/dig"
// In can be embedded in a constructor's parameter struct to take advantage of
// advanced dependency injection features.
//
// Modules should take a single parameter struct that embeds an In in order to
// provide a forward-compatible API: since adding fields to a struct is
// backward-compatible, modules can then add optional dependencies in minor
// releases.
//
// # Parameter Structs
//
// Fx constructors declare their dependencies as function parameters. This can
// quickly become unreadable if the constructor has a lot of dependencies.
//
// func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
// // ...
// }
//
// To improve the readability of constructors like this, create a struct that
// lists all the dependencies as fields and change the function to accept that
// struct instead. The new struct is called a parameter struct.
//
// Fx has first class support for parameter structs: any struct embedding
// fx.In gets treated as a parameter struct, so the individual fields in the
// struct are supplied via dependency injection. Using a parameter struct, we
// can make the constructor above much more readable:
//
// type HandlerParams struct {
// fx.In
//
// Users *UserGateway
// Comments *CommentGateway
// Posts *PostGateway
// Votes *VoteGateway
// AuthZ *AuthZGateway
// }
//
// func NewHandler(p HandlerParams) *Handler {
// // ...
// }
//
// Though it's rarely a good idea, constructors can receive any combination of
// parameter structs and parameters.
//
// func NewHandler(p HandlerParams, l *log.Logger) *Handler {
// // ...
// }
//
// # Optional Dependencies
//
// Constructors often have optional dependencies on some types: if those types are
// missing, they can operate in a degraded state. Fx supports optional
// dependencies via the `optional:"true"` tag to fields on parameter structs.
//
// type UserGatewayParams struct {
// fx.In
//
// Conn *sql.DB
// Cache *redis.Client `optional:"true"`
// }
//
// If an optional field isn't available in the container, the constructor
// receives the field's zero value.
//
// func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
// if p.Cache == nil {
// log.Print("Caching disabled")
// }
// // ...
// }
//
// Constructors that declare optional dependencies MUST gracefully handle
// situations in which those dependencies are absent.
//
// The optional tag also allows adding new dependencies without breaking
// existing consumers of the constructor.
//
// # Named Values
//
// Some use cases require the application container to hold multiple values of
// the same type. For details on producing named values, see the documentation
// for the Out type.
//
// Fx allows functions to consume named values via the `name:".."` tag on
// parameter structs. Note that both the name AND type of the fields on the
// parameter struct must match the corresponding result struct.
//
// type GatewayParams struct {
// fx.In
//
// WriteToConn *sql.DB `name:"rw"`
// ReadFromConn *sql.DB `name:"ro"`
// }
//
// The name tag may be combined with the optional tag to declare the
// dependency optional.
//
// type GatewayParams struct {
// fx.In
//
// WriteToConn *sql.DB `name:"rw"`
// ReadFromConn *sql.DB `name:"ro" optional:"true"`
// }
//
// func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
// if p.ReadFromConn == nil {
// log.Print("Warning: Using RW connection for reads")
// p.ReadFromConn = p.WriteToConn
// }
// // ...
// }
//
// # Value Groups
//
// To make it easier to produce and consume many values of the same type, Fx
// supports named, unordered collections called value groups. For details on
// producing value groups, see the documentation for the Out type.
//
// Functions can depend on a value group by requesting a slice tagged with
// `group:".."`. This will execute all constructors that provide a value to
// that group in an unspecified order, then collect all the results into a
// single slice. Keep in mind that this makes the types of the parameter and
// result struct fields different: if a group of constructors each returns
// type T, parameter structs consuming the group must use a field of type []T.
//
// type ServerParams struct {
// fx.In
//
// Handlers []Handler `group:"server"`
// }
//
// func NewServer(p ServerParams) *Server {
// server := newServer()
// for _, h := range p.Handlers {
// server.Register(h)
// }
// return server
// }
//
// Note that values in a value group are unordered. Fx makes no guarantees
// about the order in which these values will be produced.
//
// # Soft Value Groups
//
// A soft value group can be thought of as a best-attempt at populating the
// group with values from constructors that have already run. In other words,
// if a constructor's output type is only consumed by a soft value group,
// it will not be run.
//
// Note that Fx does not guarantee precise execution order of constructors
// or invokers, which means that the change in code that affects execution
// ordering of other constructors or functions will affect the values
// populated in this group.
//
// To declare a soft relationship between a group and its constructors, use
// the `soft` option on the group tag (`group:"[groupname],soft"`).
// This option is only valid for input parameters.
//
// type Params struct {
// fx.In
//
// Handlers []Handler `group:"server,soft"`
// Logger *zap.Logger
// }
//
// NewHandlerAndLogger := func() (Handler, *zap.Logger) { ... }
// NewHandler := func() Handler { ... }
// Foo := func(Params) { ... }
//
// app := fx.New(
// fx.Provide(fx.Annotate(NewHandlerAndLogger, fx.ResultTags(`group:"server"`))),
// fx.Provide(fx.Annotate(NewHandler, fx.ResultTags(`group::"server"`))),
// fx.Invoke(Foo),
// )
//
// The only constructor called is `NewHandlerAndLogger`, because this also provides
// `*zap.Logger` needed in the `Params` struct received by `Foo`. The Handlers
// group will be populated with a single Handler returned by `NewHandlerAndLogger`.
//
// In the next example, the slice `s` isn't populated as the provider would be
// called only because `strings` soft group value is its only consumer.
//
// app := fx.New(
// fx.Provide(
// fx.Annotate(
// func() (string, int) { return "hello", 42 },
// fx.ResultTags(`group:"strings"`),
// ),
// ),
// fx.Invoke(
// fx.Annotate(func(s []string) {
// // s will be an empty slice
// }, fx.ParamTags(`group:"strings,soft"`)),
// ),
// )
//
// In the next example, the slice `s` will be populated because there is a
// consumer for the same type which is not a `soft` dependency.
//
// app := fx.New(
// fx.Provide(
// fx.Annotate(
// func() string { "hello" },
// fx.ResultTags(`group:"strings"`),
// ),
// ),
// fx.Invoke(
// fx.Annotate(func(b []string) {
// // b is []string{"hello"}
// }, fx.ParamTags(`group:"strings"`)),
// ),
// fx.Invoke(
// fx.Annotate(func(s []string) {
// // s is []string{"hello"}
// }, fx.ParamTags(`group:"strings,soft"`)),
// ),
// )
//
// # Unexported fields
//
// By default, a type that embeds fx.In may not have any unexported fields. The
// following will return an error if used with Fx.
//
// type Params struct {
// fx.In
//
// Logger *zap.Logger
// mu sync.Mutex
// }
//
// If you have need of unexported fields on such a type, you may opt-into
// ignoring unexported fields by adding the ignore-unexported struct tag to the
// fx.In. For example,
//
// type Params struct {
// fx.In `ignore-unexported:"true"`
//
// Logger *zap.Logger
// mu sync.Mutex
// }
type In = dig.In
// Out is the inverse of In: it can be embedded in result structs to take
// advantage of advanced features.
//
// Modules should return a single result struct that embeds an Out in order to
// provide a forward-compatible API: since adding fields to a struct is
// backward-compatible, minor releases can provide additional types.
//
// # Result Structs
//
// Result structs are the inverse of parameter structs (discussed in the In
// documentation). These structs represent multiple outputs from a
// single function as fields. Fx treats all structs embedding fx.Out as result
// structs, so other constructors can rely on the result struct's fields
// directly.
//
// Without result structs, we sometimes have function definitions like this:
//
// func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
// // ...
// }
//
// With result structs, we can make this both more readable and easier to
// modify in the future:
//
// type Gateways struct {
// fx.Out
//
// Users *UserGateway
// Comments *CommentGateway
// Posts *PostGateway
// }
//
// func SetupGateways(conn *sql.DB) (Gateways, error) {
// // ...
// }
//
// # Named Values
//
// Some use cases require the application container to hold multiple values of
// the same type. For details on consuming named values, see the documentation
// for the In type.
//
// A constructor that produces a result struct can tag any field with
// `name:".."` to have the corresponding value added to the graph under the
// specified name. An application may contain at most one unnamed value of a
// given type, but may contain any number of named values of the same type.
//
// type ConnectionResult struct {
// fx.Out
//
// ReadWrite *sql.DB `name:"rw"`
// ReadOnly *sql.DB `name:"ro"`
// }
//
// func ConnectToDatabase(...) (ConnectionResult, error) {
// // ...
// return ConnectionResult{ReadWrite: rw, ReadOnly: ro}, nil
// }
//
// # Value Groups
//
// To make it easier to produce and consume many values of the same type, Fx
// supports named, unordered collections called value groups. For details on
// consuming value groups, see the documentation for the In type.
//
// Constructors can send values into value groups by returning a result struct
// tagged with `group:".."`.
//
// type HandlerResult struct {
// fx.Out
//
// Handler Handler `group:"server"`
// }
//
// func NewHelloHandler() HandlerResult {
// // ...
// }
//
// func NewEchoHandler() HandlerResult {
// // ...
// }
//
// Any number of constructors may provide values to this named collection, but
// the ordering of the final collection is unspecified. Keep in mind that
// value groups require parameter and result structs to use fields with
// different types: if a group of constructors each returns type T, parameter
// structs consuming the group must use a field of type []T.
//
// To provide multiple values for a group from a result struct, produce a
// slice and use the `,flatten` option on the group tag. This indicates that
// each element in the slice should be injected into the group individually.
//
// type IntResult struct {
// fx.Out
//
// Handler []int `group:"server"` // Consume as [][]int
// Handler []int `group:"server,flatten"` // Consume as []int
// }
type Out = dig.Out

58
vendor/go.uber.org/fx/internal/fxclock/clock.go generated vendored Normal file
View File

@@ -0,0 +1,58 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxclock
import (
"context"
"time"
)
// Clock defines how Fx accesses time.
// The interface is pretty minimal but it matches github.com/benbjohnson/clock.
// We intentionally don't use that interface directly;
// this keeps it a test dependency for us.
type Clock interface {
Now() time.Time
Since(time.Time) time.Duration
Sleep(time.Duration)
WithTimeout(context.Context, time.Duration) (context.Context, context.CancelFunc)
}
// System is the default implementation of Clock based on real time.
var System Clock = systemClock{}
type systemClock struct{}
func (systemClock) Now() time.Time {
return time.Now()
}
func (systemClock) Since(t time.Time) time.Duration {
return time.Since(t)
}
func (systemClock) Sleep(d time.Duration) {
time.Sleep(d)
}
func (systemClock) WithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
return context.WithTimeout(ctx, d)
}

32
vendor/go.uber.org/fx/internal/fxlog/default.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxlog
import (
"io"
"go.uber.org/fx/fxevent"
)
// DefaultLogger constructs a Logger out of io.Writer.
func DefaultLogger(w io.Writer) fxevent.Logger {
return &fxevent.ConsoleLogger{W: w}
}

91
vendor/go.uber.org/fx/internal/fxlog/spy.go generated vendored Normal file
View File

@@ -0,0 +1,91 @@
// Copyright (c) 2020-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxlog
import (
"reflect"
"sync"
"go.uber.org/fx/fxevent"
)
// Events is a list of events captured by fxlog.Spy.
type Events []fxevent.Event
// Len returns the number of events in this list.
func (es Events) Len() int { return len(es) }
// SelectByTypeName returns a new list with only events matching the specified
// type.
func (es Events) SelectByTypeName(name string) Events {
var out Events
for _, e := range es {
if reflect.TypeOf(e).Elem().Name() == name {
out = append(out, e)
}
}
return out
}
// Spy is an Fx event logger that captures emitted events and/or logged
// statements. It may be used in tests of Fx logs.
type Spy struct {
mu sync.RWMutex
events Events
}
var _ fxevent.Logger = &Spy{}
// LogEvent appends an Event.
func (s *Spy) LogEvent(event fxevent.Event) {
s.mu.Lock()
s.events = append(s.events, event)
s.mu.Unlock()
}
// Events returns all captured events.
func (s *Spy) Events() Events {
s.mu.RLock()
defer s.mu.RUnlock()
events := make(Events, len(s.events))
copy(events, s.events)
return events
}
// EventTypes returns all captured event types.
func (s *Spy) EventTypes() []string {
s.mu.RLock()
defer s.mu.RUnlock()
types := make([]string, len(s.events))
for i, e := range s.events {
types[i] = reflect.TypeOf(e).Elem().Name()
}
return types
}
// Reset clears all messages and events from the Spy.
func (s *Spy) Reset() {
s.mu.Lock()
s.events = s.events[:0]
s.mu.Unlock()
}

86
vendor/go.uber.org/fx/internal/fxreflect/fxreflect.go generated vendored Normal file
View File

@@ -0,0 +1,86 @@
// Copyright (c) 2019-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxreflect
import (
"fmt"
"net/url"
"reflect"
"regexp"
"runtime"
"strings"
)
// Match from beginning of the line until the first `vendor/` (non-greedy)
var vendorRe = regexp.MustCompile("^.*?/vendor/")
// sanitize makes the function name suitable for logging display. It removes
// url-encoded elements from the `dot.git` package names and shortens the
// vendored paths.
func sanitize(function string) string {
// Use the stdlib to un-escape any package import paths which can happen
// in the case of the "dot-git" postfix. Seems like a bug in stdlib =/
if unescaped, err := url.QueryUnescape(function); err == nil {
function = unescaped
}
// strip everything prior to the vendor
return vendorRe.ReplaceAllString(function, "vendor/")
}
// Caller returns the formatted calling func name
func Caller() string {
return CallerStack(1, 0).CallerName()
}
// FuncName returns a funcs formatted name
func FuncName(fn interface{}) string {
fnV := reflect.ValueOf(fn)
if fnV.Kind() != reflect.Func {
return fmt.Sprint(fn)
}
function := runtime.FuncForPC(fnV.Pointer()).Name()
return fmt.Sprintf("%s()", sanitize(function))
}
// Ascend the call stack until we leave the Fx production code. This allows us
// to avoid hard-coding a frame skip, which makes this code work well even
// when it's wrapped.
func shouldIgnoreFrame(f Frame) bool {
// Treat test files as leafs.
if strings.Contains(f.File, "_test.go") {
return false
}
// The unique, fully-qualified name for all functions begins with
// "{{importPath}}.". We'll ignore Fx and its subpackages.
s := strings.TrimPrefix(f.Function, "go.uber.org/fx")
if len(s) > 0 && s[0] == '.' || s[0] == '/' {
// We want to match,
// go.uber.org/fx.Foo
// go.uber.org/fx/something.Foo
// But not, go.uber.org/fxfoo
return true
}
return false
}

158
vendor/go.uber.org/fx/internal/fxreflect/stack.go generated vendored Normal file
View File

@@ -0,0 +1,158 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fxreflect
import (
"fmt"
"io"
"runtime"
"strings"
)
// Frame holds information about a single frame in the call stack.
type Frame struct {
// Unique, package path-qualified name for the function of this call
// frame.
Function string
// File and line number of our location in the frame.
//
// Note that the line number does not refer to where the function was
// defined but where in the function the next call was made.
File string
Line int
}
func (f Frame) String() string {
// This takes the following forms.
// (path/to/file.go)
// (path/to/file.go:42)
// path/to/package.MyFunction
// path/to/package.MyFunction (path/to/file.go)
// path/to/package.MyFunction (path/to/file.go:42)
var sb strings.Builder
sb.WriteString(f.Function)
if len(f.File) > 0 {
if sb.Len() > 0 {
sb.WriteRune(' ')
}
fmt.Fprintf(&sb, "(%v", f.File)
if f.Line > 0 {
fmt.Fprintf(&sb, ":%d", f.Line)
}
sb.WriteRune(')')
}
if sb.Len() == 0 {
return "unknown"
}
return sb.String()
}
const _defaultCallersDepth = 8
// Stack is a stack of call frames.
//
// Formatted with %v, the output is in a single-line, in the form,
//
// foo/bar.Baz() (path/to/foo.go:42); bar/baz.Qux() (bar/baz/qux.go:12); ...
//
// Formatted with %+v, the output is in the form,
//
// foo/bar.Baz()
// path/to/foo.go:42
// bar/baz.Qux()
// bar/baz/qux.go:12
type Stack []Frame
// String returns a single-line, semi-colon representation of a Stack.
// For a list of strings where each represents one frame, use Strings.
// For a cleaner multi-line representation, use %+v.
func (fs Stack) String() string {
return strings.Join(fs.Strings(), "; ")
}
// Strings returns a list of strings, each representing a frame in the stack.
// Each line will be in the form,
//
// foo/bar.Baz() (path/to/foo.go:42)
func (fs Stack) Strings() []string {
items := make([]string, len(fs))
for i, f := range fs {
items[i] = f.String()
}
return items
}
// Format implements fmt.Formatter to handle "%+v".
func (fs Stack) Format(w fmt.State, c rune) {
if !w.Flag('+') {
// Without %+v, fall back to String().
io.WriteString(w, fs.String())
return
}
for _, f := range fs {
fmt.Fprintln(w, f.Function)
fmt.Fprintf(w, "\t%v:%v\n", f.File, f.Line)
}
}
// CallerName returns the name of the first caller in this stack that isn't
// owned by the Fx library.
func (fs Stack) CallerName() string {
for _, f := range fs {
if shouldIgnoreFrame(f) {
continue
}
return f.Function
}
return "n/a"
}
// CallerStack returns the call stack for the calling function, up to depth frames
// deep, skipping the provided number of frames, not including Callers itself.
//
// If zero, depth defaults to 8.
func CallerStack(skip, depth int) Stack {
if depth <= 0 {
depth = _defaultCallersDepth
}
pcs := make([]uintptr, depth)
// +2 to skip this frame and runtime.Callers.
n := runtime.Callers(skip+2, pcs)
pcs = pcs[:n] // truncate to number of frames actually read
result := make([]Frame, 0, n)
frames := runtime.CallersFrames(pcs)
for f, more := frames.Next(); more; f, more = frames.Next() {
result = append(result, Frame{
Function: sanitize(f.Function),
File: f.File,
Line: f.Line,
})
}
return result
}

401
vendor/go.uber.org/fx/internal/lifecycle/lifecycle.go generated vendored Normal file
View File

@@ -0,0 +1,401 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package lifecycle
import (
"context"
"errors"
"fmt"
"io"
"reflect"
"strings"
"sync"
"time"
"go.uber.org/fx/fxevent"
"go.uber.org/fx/internal/fxclock"
"go.uber.org/fx/internal/fxreflect"
"go.uber.org/multierr"
)
// Reflection types for each of the supported hook function signatures. These
// are used in cases in which the Callable constraint matches a user-defined
// function type that cannot be converted to an underlying function type with
// a conventional conversion or type switch.
var (
_reflFunc = reflect.TypeOf(Func(nil))
_reflErrorFunc = reflect.TypeOf(ErrorFunc(nil))
_reflContextFunc = reflect.TypeOf(ContextFunc(nil))
_reflContextErrorFunc = reflect.TypeOf(ContextErrorFunc(nil))
)
// Discrete function signatures that are allowed as part of a [Callable].
type (
// A Func can be converted to a ContextErrorFunc.
Func = func()
// An ErrorFunc can be converted to a ContextErrorFunc.
ErrorFunc = func() error
// A ContextFunc can be converted to a ContextErrorFunc.
ContextFunc = func(context.Context)
// A ContextErrorFunc is used as a [Hook.OnStart] or [Hook.OnStop]
// function.
ContextErrorFunc = func(context.Context) error
)
// A Callable is a constraint that matches functions that are, or can be
// converted to, functions suitable for a Hook.
//
// Callable must be identical to [fx.HookFunc].
type Callable interface {
~Func | ~ErrorFunc | ~ContextFunc | ~ContextErrorFunc
}
// Wrap wraps x into a ContextErrorFunc suitable for a Hook.
func Wrap[T Callable](x T) (ContextErrorFunc, string) {
if x == nil {
return nil, ""
}
switch fn := any(x).(type) {
case Func:
return func(context.Context) error {
fn()
return nil
}, fxreflect.FuncName(x)
case ErrorFunc:
return func(context.Context) error {
return fn()
}, fxreflect.FuncName(x)
case ContextFunc:
return func(ctx context.Context) error {
fn(ctx)
return nil
}, fxreflect.FuncName(x)
case ContextErrorFunc:
return fn, fxreflect.FuncName(x)
}
// Since (1) we're already using reflect in Fx, (2) we're not particularly
// concerned with performance, and (3) unsafe would require discrete build
// targets for appengine (etc), just use reflect to convert user-defined
// function types to their underlying function types and then call Wrap
// again with the converted value.
reflVal := reflect.ValueOf(x)
switch {
case reflVal.CanConvert(_reflFunc):
return Wrap(reflVal.Convert(_reflFunc).Interface().(Func))
case reflVal.CanConvert(_reflErrorFunc):
return Wrap(reflVal.Convert(_reflErrorFunc).Interface().(ErrorFunc))
case reflVal.CanConvert(_reflContextFunc):
return Wrap(reflVal.Convert(_reflContextFunc).Interface().(ContextFunc))
default:
// Is already convertible to ContextErrorFunc.
return Wrap(reflVal.Convert(_reflContextErrorFunc).Interface().(ContextErrorFunc))
}
}
// A Hook is a pair of start and stop callbacks, either of which can be nil,
// plus a string identifying the supplier of the hook.
type Hook struct {
OnStart func(context.Context) error
OnStop func(context.Context) error
OnStartName string
OnStopName string
callerFrame fxreflect.Frame
}
type appState int
const (
stopped appState = iota
starting
incompleteStart
started
stopping
)
func (as appState) String() string {
switch as {
case stopped:
return "stopped"
case starting:
return "starting"
case incompleteStart:
return "incompleteStart"
case started:
return "started"
case stopping:
return "stopping"
default:
return "invalidState"
}
}
// Lifecycle coordinates application lifecycle hooks.
type Lifecycle struct {
clock fxclock.Clock
logger fxevent.Logger
state appState
hooks []Hook
numStarted int
startRecords HookRecords
stopRecords HookRecords
runningHook Hook
mu sync.Mutex
}
// New constructs a new Lifecycle.
func New(logger fxevent.Logger, clock fxclock.Clock) *Lifecycle {
return &Lifecycle{logger: logger, clock: clock}
}
// Append adds a Hook to the lifecycle.
func (l *Lifecycle) Append(hook Hook) {
// Save the caller's stack frame to report file/line number.
if f := fxreflect.CallerStack(2, 0); len(f) > 0 {
hook.callerFrame = f[0]
}
l.hooks = append(l.hooks, hook)
}
// Start runs all OnStart hooks, returning immediately if it encounters an
// error.
func (l *Lifecycle) Start(ctx context.Context) error {
if ctx == nil {
return errors.New("called OnStart with nil context")
}
l.mu.Lock()
if l.state != stopped {
defer l.mu.Unlock()
return fmt.Errorf("attempted to start lifecycle when in state: %v", l.state)
}
l.numStarted = 0
l.state = starting
l.startRecords = make(HookRecords, 0, len(l.hooks))
l.mu.Unlock()
var returnState appState = incompleteStart
defer func() {
l.mu.Lock()
l.state = returnState
l.mu.Unlock()
}()
for _, hook := range l.hooks {
// if ctx has cancelled, bail out of the loop.
if err := ctx.Err(); err != nil {
return err
}
if hook.OnStart != nil {
l.mu.Lock()
l.runningHook = hook
l.mu.Unlock()
runtime, err := l.runStartHook(ctx, hook)
if err != nil {
return err
}
l.mu.Lock()
l.startRecords = append(l.startRecords, HookRecord{
CallerFrame: hook.callerFrame,
Func: hook.OnStart,
Runtime: runtime,
})
l.mu.Unlock()
}
l.numStarted++
}
returnState = started
return nil
}
func (l *Lifecycle) runStartHook(ctx context.Context, hook Hook) (runtime time.Duration, err error) {
funcName := hook.OnStartName
if len(funcName) == 0 {
funcName = fxreflect.FuncName(hook.OnStart)
}
l.logger.LogEvent(&fxevent.OnStartExecuting{
CallerName: hook.callerFrame.Function,
FunctionName: funcName,
})
defer func() {
l.logger.LogEvent(&fxevent.OnStartExecuted{
CallerName: hook.callerFrame.Function,
FunctionName: funcName,
Runtime: runtime,
Err: err,
})
}()
begin := l.clock.Now()
err = hook.OnStart(ctx)
return l.clock.Since(begin), err
}
// Stop runs any OnStop hooks whose OnStart counterpart succeeded. OnStop
// hooks run in reverse order.
func (l *Lifecycle) Stop(ctx context.Context) error {
if ctx == nil {
return errors.New("called OnStop with nil context")
}
l.mu.Lock()
if l.state != started && l.state != incompleteStart && l.state != starting {
defer l.mu.Unlock()
return nil
}
l.state = stopping
l.mu.Unlock()
defer func() {
l.mu.Lock()
l.state = stopped
l.mu.Unlock()
}()
l.mu.Lock()
l.stopRecords = make(HookRecords, 0, l.numStarted)
// Take a snapshot of hook state to avoid races.
allHooks := l.hooks[:]
numStarted := l.numStarted
l.mu.Unlock()
// Run backward from last successful OnStart.
var errs []error
for ; numStarted > 0; numStarted-- {
if err := ctx.Err(); err != nil {
return err
}
hook := allHooks[numStarted-1]
if hook.OnStop == nil {
continue
}
l.mu.Lock()
l.runningHook = hook
l.mu.Unlock()
runtime, err := l.runStopHook(ctx, hook)
if err != nil {
// For best-effort cleanup, keep going after errors.
errs = append(errs, err)
}
l.mu.Lock()
l.stopRecords = append(l.stopRecords, HookRecord{
CallerFrame: hook.callerFrame,
Func: hook.OnStop,
Runtime: runtime,
})
l.mu.Unlock()
}
return multierr.Combine(errs...)
}
func (l *Lifecycle) runStopHook(ctx context.Context, hook Hook) (runtime time.Duration, err error) {
funcName := hook.OnStopName
if len(funcName) == 0 {
funcName = fxreflect.FuncName(hook.OnStop)
}
l.logger.LogEvent(&fxevent.OnStopExecuting{
CallerName: hook.callerFrame.Function,
FunctionName: funcName,
})
defer func() {
l.logger.LogEvent(&fxevent.OnStopExecuted{
CallerName: hook.callerFrame.Function,
FunctionName: funcName,
Runtime: runtime,
Err: err,
})
}()
begin := l.clock.Now()
err = hook.OnStop(ctx)
return l.clock.Since(begin), err
}
// RunningHookCaller returns the name of the hook that was running when a Start/Stop
// hook timed out.
func (l *Lifecycle) RunningHookCaller() string {
l.mu.Lock()
defer l.mu.Unlock()
return l.runningHook.callerFrame.Function
}
// HookRecord keeps track of each Hook's execution time, the caller that appended the Hook, and function that ran as the Hook.
type HookRecord struct {
CallerFrame fxreflect.Frame // stack frame of the caller
Func func(context.Context) error // function that ran as sanitized name
Runtime time.Duration // how long the hook ran
}
// HookRecords is a Stringer wrapper of HookRecord slice.
type HookRecords []HookRecord
func (rs HookRecords) Len() int {
return len(rs)
}
func (rs HookRecords) Less(i, j int) bool {
// Sort by runtime, greater ones at top.
return rs[i].Runtime > rs[j].Runtime
}
func (rs HookRecords) Swap(i, j int) {
rs[i], rs[j] = rs[j], rs[i]
}
// Used for logging startup errors.
func (rs HookRecords) String() string {
var b strings.Builder
for _, r := range rs {
fmt.Fprintf(&b, "%s took %v from %s",
fxreflect.FuncName(r.Func), r.Runtime, r.CallerFrame)
}
return b.String()
}
// Format implements fmt.Formatter to handle "%+v".
func (rs HookRecords) Format(w fmt.State, c rune) {
if !w.Flag('+') {
// Without %+v, fall back to String().
io.WriteString(w, rs.String())
return
}
for _, r := range rs {
fmt.Fprintf(w, "\n%s took %v from:\n\t%+v",
fxreflect.FuncName(r.Func),
r.Runtime,
r.CallerFrame)
}
fmt.Fprintf(w, "\n")
}

110
vendor/go.uber.org/fx/invoke.go generated vendored Normal file
View File

@@ -0,0 +1,110 @@
// Copyright (c) 2019-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"strings"
"go.uber.org/fx/internal/fxreflect"
)
// Invoke registers functions that are executed eagerly on application start.
// Arguments for these invocations are built using the constructors registered
// by Provide. Passing multiple Invoke options appends the new invocations to
// the application's existing list.
//
// Unlike constructors, invocations are always executed, and they're always
// run in order. Invocations may have any number of returned values.
// If the final returned object is an error, it indicates whether the operation
// was successful.
// All other returned values are discarded.
//
// Invokes registered in [Module]s are run before the ones registered at the
// scope of the parent. Invokes within the same Module is run in the order
// they were provided. For example,
//
// fx.New(
// fx.Invoke(func3),
// fx.Module("someModule",
// fx.Invoke(func1),
// fx.Invoke(func2),
// ),
// fx.Invoke(func4),
// )
//
// invokes func1, func2, func3, func4 in that order.
//
// Typically, invoked functions take a handful of high-level objects (whose
// constructors depend on lower-level objects) and introduce them to each
// other. This kick-starts the application by forcing it to instantiate a
// variety of types.
//
// To see an invocation in use, read through the package-level example. For
// advanced features, including optional parameters and named instances, see
// the documentation of the In and Out types.
func Invoke(funcs ...interface{}) Option {
return invokeOption{
Targets: funcs,
Stack: fxreflect.CallerStack(1, 0),
}
}
type invokeOption struct {
Targets []interface{}
Stack fxreflect.Stack
}
func (o invokeOption) apply(mod *module) {
for _, target := range o.Targets {
mod.invokes = append(mod.invokes, invoke{
Target: target,
Stack: o.Stack,
})
}
}
func (o invokeOption) String() string {
items := make([]string, len(o.Targets))
for i, f := range o.Targets {
items[i] = fxreflect.FuncName(f)
}
return fmt.Sprintf("fx.Invoke(%s)", strings.Join(items, ", "))
}
func runInvoke(c container, i invoke) error {
fn := i.Target
switch fn := fn.(type) {
case Option:
return fmt.Errorf("fx.Option should be passed to fx.New directly, "+
"not to fx.Invoke: fx.Invoke received %v from:\n%+v",
fn, i.Stack)
case annotated:
af, err := fn.Build()
if err != nil {
return err
}
return c.Invoke(af)
default:
return c.Invoke(fn)
}
}

147
vendor/go.uber.org/fx/lifecycle.go generated vendored Normal file
View File

@@ -0,0 +1,147 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"context"
"go.uber.org/fx/internal/lifecycle"
)
// A HookFunc is a function that can be used as a [Hook].
type HookFunc interface {
~func() | ~func() error | ~func(context.Context) | ~func(context.Context) error
}
// Lifecycle allows constructors to register callbacks that are executed on
// application start and stop. See the documentation for App for details on Fx
// applications' initialization, startup, and shutdown logic.
type Lifecycle interface {
Append(Hook)
}
// A Hook is a pair of start and stop callbacks, either of which can be nil.
// If a Hook's OnStart callback isn't executed (because a previous OnStart
// failure short-circuited application startup), its OnStop callback won't be
// executed.
type Hook struct {
OnStart func(context.Context) error
OnStop func(context.Context) error
onStartName string
onStopName string
}
// StartHook returns a new Hook with start as its [Hook.OnStart] function,
// wrapping its signature as needed. For example, given the following function:
//
// func myhook() {
// fmt.Println("hook called")
// }
//
// then calling:
//
// lifecycle.Append(StartHook(myfunc))
//
// is functionally equivalent to calling:
//
// lifecycle.Append(fx.Hook{
// OnStart: func(context.Context) error {
// myfunc()
// return nil
// },
// })
//
// The same is true for all functions that satisfy the HookFunc constraint.
// Note that any context.Context parameter or error return will be propagated
// as expected. If propagation is not intended, users should instead provide a
// closure that discards the undesired value(s), or construct a Hook directly.
func StartHook[T HookFunc](start T) Hook {
onstart, startname := lifecycle.Wrap(start)
return Hook{
OnStart: onstart,
onStartName: startname,
}
}
// StopHook returns a new Hook with stop as its [Hook.OnStop] function,
// wrapping its signature as needed. For example, given the following function:
//
// func myhook() {
// fmt.Println("hook called")
// }
//
// then calling:
//
// lifecycle.Append(StopHook(myfunc))
//
// is functionally equivalent to calling:
//
// lifecycle.Append(fx.Hook{
// OnStop: func(context.Context) error {
// myfunc()
// return nil
// },
// })
//
// The same is true for all functions that satisfy the HookFunc constraint.
// Note that any context.Context parameter or error return will be propagated
// as expected. If propagation is not intended, users should instead provide a
// closure that discards the undesired value(s), or construct a Hook directly.
func StopHook[T HookFunc](stop T) Hook {
onstop, stopname := lifecycle.Wrap(stop)
return Hook{
OnStop: onstop,
onStopName: stopname,
}
}
// StartStopHook returns a new Hook with start as its [Hook.OnStart] function
// and stop as its [Hook.OnStop] function, independently wrapping the signature
// of each as needed.
func StartStopHook[T1 HookFunc, T2 HookFunc](start T1, stop T2) Hook {
var (
onstart, startname = lifecycle.Wrap(start)
onstop, stopname = lifecycle.Wrap(stop)
)
return Hook{
OnStart: onstart,
OnStop: onstop,
onStartName: startname,
onStopName: stopname,
}
}
type lifecycleWrapper struct {
*lifecycle.Lifecycle
}
func (l *lifecycleWrapper) Append(h Hook) {
l.Lifecycle.Append(lifecycle.Hook{
OnStart: h.OnStart,
OnStop: h.OnStop,
OnStartName: h.onStartName,
OnStopName: h.onStopName,
})
}

50
vendor/go.uber.org/fx/log.go generated vendored Normal file
View File

@@ -0,0 +1,50 @@
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"go.uber.org/fx/fxevent"
)
// logBuffer will buffer all messages until a logger has been
// initialized.
type logBuffer struct {
events []fxevent.Event
logger fxevent.Logger
}
// LogEvent buffers or logs an event.
func (l *logBuffer) LogEvent(event fxevent.Event) {
if l.logger == nil {
l.events = append(l.events, event)
} else {
l.logger.LogEvent(event)
}
}
// Connect flushes out all buffered events to a logger and resets them.
func (l *logBuffer) Connect(logger fxevent.Logger) {
l.logger = logger
for _, e := range l.events {
logger.LogEvent(e)
}
l.events = nil
}

372
vendor/go.uber.org/fx/module.go generated vendored Normal file
View File

@@ -0,0 +1,372 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"go.uber.org/dig"
"go.uber.org/fx/fxevent"
"go.uber.org/fx/internal/fxreflect"
"go.uber.org/multierr"
)
// A container represents a set of constructors to provide
// dependencies, and a set of functions to invoke once all the
// dependencies have been initialized.
//
// This definition corresponds to the dig.Container and dig.Scope.
type container interface {
Invoke(interface{}, ...dig.InvokeOption) error
Provide(interface{}, ...dig.ProvideOption) error
Decorate(interface{}, ...dig.DecorateOption) error
}
// Module is a named group of zero or more fx.Options.
// A Module creates a scope in which certain operations are taken
// place. For more information, see [Decorate], [Replace], or [Invoke].
func Module(name string, opts ...Option) Option {
mo := moduleOption{
name: name,
location: fxreflect.CallerStack(1, 2)[0],
options: opts,
}
return mo
}
type moduleOption struct {
name string
location fxreflect.Frame
options []Option
}
func (o moduleOption) String() string {
return fmt.Sprintf("fx.Module(%q, %v)", o.name, o.options)
}
func (o moduleOption) apply(mod *module) {
// This get called on any submodules' that are declared
// as part of another module.
// 1. Create a new module with the parent being the specified
// module.
// 2. Apply child Options on the new module.
// 3. Append it to the parent module.
// Create trace as parent's trace with this module's location pre-pended.
trace := append([]string{fmt.Sprintf("%v (%v)", o.location, o.name)}, mod.trace...)
newModule := &module{
name: o.name,
parent: mod,
trace: trace,
app: mod.app,
}
for _, opt := range o.options {
opt.apply(newModule)
}
mod.modules = append(mod.modules, newModule)
}
type module struct {
parent *module
name string
trace []string
scope scope
provides []provide
invokes []invoke
decorators []decorator
modules []*module
app *App
log fxevent.Logger
fallbackLogger fxevent.Logger
logConstructor *provide
}
// scope is a private wrapper interface for dig.Container and dig.Scope.
// We can consider moving this into Fx using type constraints after Go 1.20
// is released and 1.17 is deprecated.
type scope interface {
Decorate(f interface{}, opts ...dig.DecorateOption) error
Invoke(f interface{}, opts ...dig.InvokeOption) error
Provide(f interface{}, opts ...dig.ProvideOption) error
Scope(name string, opts ...dig.ScopeOption) *dig.Scope
String() string
}
// builds the Scopes using the App's Container. Note that this happens
// after applyModules' are called because the App's Container needs to
// be built for any Scopes to be initialized, and applys' should be called
// before the Container can get initialized.
func (m *module) build(app *App, root *dig.Container) {
if m.parent == nil {
m.scope = root
} else {
parentScope := m.parent.scope
m.scope = parentScope.Scope(m.name)
// use parent module's logger by default
m.log = m.parent.log
}
if m.logConstructor != nil {
// Since user supplied a custom logger, use a buffered logger
// to hold all messages until user supplied logger is
// instantiated. Then we flush those messages after fully
// constructing the custom logger.
m.fallbackLogger, m.log = m.log, new(logBuffer)
}
for _, mod := range m.modules {
mod.build(app, root)
}
}
func (m *module) provideAll() {
for _, p := range m.provides {
m.provide(p)
}
for _, m := range m.modules {
m.provideAll()
}
}
func (m *module) provide(p provide) {
if m.app.err != nil {
return
}
if p.IsSupply {
m.supply(p)
return
}
funcName := fxreflect.FuncName(p.Target)
var info dig.ProvideInfo
opts := []dig.ProvideOption{
dig.FillProvideInfo(&info),
dig.Export(!p.Private),
dig.WithProviderCallback(func(ci dig.CallbackInfo) {
m.log.LogEvent(&fxevent.Run{
Name: funcName,
Kind: "provide",
ModuleName: m.name,
Err: ci.Error,
})
}),
}
if err := runProvide(m.scope, p, opts...); err != nil {
m.app.err = err
}
outputNames := make([]string, len(info.Outputs))
for i, o := range info.Outputs {
outputNames[i] = o.String()
}
m.log.LogEvent(&fxevent.Provided{
ConstructorName: funcName,
StackTrace: p.Stack.Strings(),
ModuleTrace: append([]string{p.Stack[0].String()}, m.trace...),
ModuleName: m.name,
OutputTypeNames: outputNames,
Err: m.app.err,
Private: p.Private,
})
}
func (m *module) supply(p provide) {
typeName := p.SupplyType.String()
opts := []dig.ProvideOption{
dig.Export(!p.Private),
dig.WithProviderCallback(func(ci dig.CallbackInfo) {
m.log.LogEvent(&fxevent.Run{
Name: fmt.Sprintf("stub(%v)", typeName),
Kind: "supply",
ModuleName: m.name,
})
}),
}
if err := runProvide(m.scope, p, opts...); err != nil {
m.app.err = err
}
m.log.LogEvent(&fxevent.Supplied{
TypeName: typeName,
StackTrace: p.Stack.Strings(),
ModuleTrace: append([]string{p.Stack[0].String()}, m.trace...),
ModuleName: m.name,
Err: m.app.err,
})
}
// Constructs custom loggers for all modules in the tree
func (m *module) constructAllCustomLoggers() {
if m.logConstructor != nil {
if buffer, ok := m.log.(*logBuffer); ok {
// default to parent's logger if custom logger constructor fails
if err := m.constructCustomLogger(buffer); err != nil {
m.app.err = multierr.Append(m.app.err, err)
m.log = m.fallbackLogger
buffer.Connect(m.log)
}
}
m.fallbackLogger = nil
} else if m.parent != nil {
m.log = m.parent.log
}
for _, mod := range m.modules {
mod.constructAllCustomLoggers()
}
}
// Mirroring the behavior of app.constructCustomLogger
func (m *module) constructCustomLogger(buffer *logBuffer) (err error) {
p := m.logConstructor
fname := fxreflect.FuncName(p.Target)
defer func() {
m.log.LogEvent(&fxevent.LoggerInitialized{
Err: err,
ConstructorName: fname,
})
}()
// TODO: Use dig.FillProvideInfo to inspect the provided constructor
// and fail the application if its signature didn't match.
if err := m.scope.Provide(p.Target); err != nil {
return fmt.Errorf("fx.WithLogger(%v) from:\n%+v\nin Module: %q\nFailed: %w",
fname, p.Stack, m.name, err)
}
return m.scope.Invoke(func(log fxevent.Logger) {
m.log = log
buffer.Connect(log)
})
}
func (m *module) executeInvokes() error {
for _, m := range m.modules {
if err := m.executeInvokes(); err != nil {
return err
}
}
for _, invoke := range m.invokes {
if err := m.executeInvoke(invoke); err != nil {
return err
}
}
return nil
}
func (m *module) executeInvoke(i invoke) (err error) {
fnName := fxreflect.FuncName(i.Target)
m.log.LogEvent(&fxevent.Invoking{
FunctionName: fnName,
ModuleName: m.name,
})
err = runInvoke(m.scope, i)
m.log.LogEvent(&fxevent.Invoked{
FunctionName: fnName,
ModuleName: m.name,
Err: err,
Trace: fmt.Sprintf("%+v", i.Stack), // format stack trace as multi-line
})
return err
}
func (m *module) decorateAll() error {
for _, d := range m.decorators {
if err := m.decorate(d); err != nil {
return err
}
}
for _, m := range m.modules {
if err := m.decorateAll(); err != nil {
return err
}
}
return nil
}
func (m *module) decorate(d decorator) (err error) {
if d.IsReplace {
return m.replace(d)
}
funcName := fxreflect.FuncName(d.Target)
var info dig.DecorateInfo
opts := []dig.DecorateOption{
dig.FillDecorateInfo(&info),
dig.WithDecoratorCallback(func(ci dig.CallbackInfo) {
m.log.LogEvent(&fxevent.Run{
Name: funcName,
Kind: "decorate",
ModuleName: m.name,
Err: ci.Error,
})
}),
}
err = runDecorator(m.scope, d, opts...)
outputNames := make([]string, len(info.Outputs))
for i, o := range info.Outputs {
outputNames[i] = o.String()
}
m.log.LogEvent(&fxevent.Decorated{
DecoratorName: funcName,
StackTrace: d.Stack.Strings(),
ModuleTrace: append([]string{d.Stack[0].String()}, m.trace...),
ModuleName: m.name,
OutputTypeNames: outputNames,
Err: err,
})
return err
}
func (m *module) replace(d decorator) error {
typeName := d.ReplaceType.String()
opts := []dig.DecorateOption{
dig.WithDecoratorCallback(func(ci dig.CallbackInfo) {
m.log.LogEvent(&fxevent.Run{
Name: fmt.Sprintf("stub(%v)", typeName),
Kind: "replace",
ModuleName: m.name,
Err: ci.Error,
})
}),
}
err := runDecorator(m.scope, d, opts...)
m.log.LogEvent(&fxevent.Replaced{
ModuleName: m.name,
StackTrace: d.Stack.Strings(),
ModuleTrace: append([]string{d.Stack[0].String()}, m.trace...),
OutputTypeNames: []string{typeName},
Err: err,
})
return err
}

115
vendor/go.uber.org/fx/populate.go generated vendored Normal file
View File

@@ -0,0 +1,115 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"reflect"
)
// Populate sets targets with values from the dependency injection container
// during application initialization. All targets must be pointers to the
// values that must be populated. Pointers to structs that embed In are
// supported, which can be used to populate multiple values in a struct.
//
// Annotating each pointer with ParamTags is also supported as a shorthand
// to passing a pointer to a struct that embeds In with field tags. For example:
//
// var a A
// var b B
// fx.Populate(
// fx.Annotate(
// &a,
// fx.ParamTags(`name:"A"`)
// ),
// fx.Annotate(
// &b,
// fx.ParamTags(`name:"B"`)
// )
// )
//
// Code above is equivalent to the following:
//
// type Target struct {
// fx.In
//
// a A `name:"A"`
// b B `name:"B"`
// }
// var target Target
// ...
// fx.Populate(&target)
//
// This is most helpful in unit tests: it lets tests leverage Fx's automatic
// constructor wiring to build a few structs, but then extract those structs
// for further testing.
func Populate(targets ...interface{}) Option {
// Validate all targets are non-nil pointers.
fields := make([]reflect.StructField, len(targets)+1)
fields[0] = reflect.StructField{
Name: "In",
Type: reflect.TypeOf(In{}),
Anonymous: true,
}
for i, t := range targets {
if t == nil {
return Error(fmt.Errorf("failed to Populate: target %v is nil", i+1))
}
var (
rt reflect.Type
tag reflect.StructTag
)
switch t := t.(type) {
case annotated:
rt = reflect.TypeOf(t.Target)
tag = reflect.StructTag(t.ParamTags[0])
targets[i] = t.Target
default:
rt = reflect.TypeOf(t)
}
if rt.Kind() != reflect.Ptr {
return Error(fmt.Errorf("failed to Populate: target %v is not a pointer type, got %T", i+1, t))
}
fields[i+1] = reflect.StructField{
Name: fmt.Sprintf("Field%d", i),
Type: rt.Elem(),
Tag: tag,
}
}
// Build a function that looks like:
//
// func(t1 T1, t2 T2, ...) {
// *targets[0] = t1
// *targets[1] = t2
// [...]
// }
//
fnType := reflect.FuncOf([]reflect.Type{reflect.StructOf(fields)}, nil, false /* variadic */)
fn := reflect.MakeFunc(fnType, func(args []reflect.Value) []reflect.Value {
arg := args[0]
for i, target := range targets {
reflect.ValueOf(target).Elem().Set(arg.Field(i + 1))
}
return nil
})
return Invoke(fn.Interface())
}

36
vendor/go.uber.org/fx/printer_writer.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
// Copyright (c) 2020-2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import "io"
type printerWriter struct{ p Printer }
// writerFromPrinter returns an implementation of io.Writer used to support
// Logger option which implements Printer interface.
func writerFromPrinter(p Printer) io.Writer {
return &printerWriter{p: p}
}
func (w *printerWriter) Write(b []byte) (n int, err error) {
w.p.Printf(string(b))
return len(b), nil
}

187
vendor/go.uber.org/fx/provide.go generated vendored Normal file
View File

@@ -0,0 +1,187 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"reflect"
"strings"
"go.uber.org/dig"
"go.uber.org/fx/internal/fxreflect"
)
// Provide registers any number of constructor functions, teaching the
// application how to instantiate various types. The supplied constructor
// function(s) may depend on other types available in the application, must
// return one or more objects, and may return an error. For example:
//
// // Constructs type *C, depends on *A and *B.
// func(*A, *B) *C
//
// // Constructs type *C, depends on *A and *B, and indicates failure by
// // returning an error.
// func(*A, *B) (*C, error)
//
// // Constructs types *B and *C, depends on *A, and can fail.
// func(*A) (*B, *C, error)
//
// The order in which constructors are provided doesn't matter, and passing
// multiple Provide options appends to the application's collection of
// constructors. Constructors are called only if one or more of their returned
// types are needed, and their results are cached for reuse (so instances of a
// type are effectively singletons within an application). Taken together,
// these properties make it perfectly reasonable to Provide a large number of
// constructors even if only a fraction of them are used.
//
// See the documentation of the In and Out types for advanced features,
// including optional parameters and named instances.
//
// See the documentation for [Private] for restricting access to constructors.
//
// Constructor functions should perform as little external interaction as
// possible, and should avoid spawning goroutines. Things like server listen
// loops, background timer loops, and background processing goroutines should
// instead be managed using Lifecycle callbacks.
func Provide(constructors ...interface{}) Option {
return provideOption{
Targets: constructors,
Stack: fxreflect.CallerStack(1, 0),
}
}
type provideOption struct {
Targets []interface{}
Stack fxreflect.Stack
}
func (o provideOption) apply(mod *module) {
var private bool
targets := make([]interface{}, 0, len(o.Targets))
for _, target := range o.Targets {
if _, ok := target.(privateOption); ok {
private = true
continue
}
targets = append(targets, target)
}
for _, target := range targets {
mod.provides = append(mod.provides, provide{
Target: target,
Stack: o.Stack,
Private: private,
})
}
}
type privateOption struct{}
// Private is an option that can be passed as an argument to [Provide] to
// restrict access to the constructors being provided. Specifically,
// corresponding constructors can only be used within the current module
// or modules the current module contains. Other modules that contain this
// module won't be able to use the constructor.
//
// For example, the following would fail because the app doesn't have access
// to the inner module's constructor.
//
// fx.New(
// fx.Module("SubModule", fx.Provide(func() int { return 0 }, fx.Private)),
// fx.Invoke(func(a int) {}),
// )
var Private = privateOption{}
func (o provideOption) String() string {
items := make([]string, len(o.Targets))
for i, c := range o.Targets {
items[i] = fxreflect.FuncName(c)
}
return fmt.Sprintf("fx.Provide(%s)", strings.Join(items, ", "))
}
func runProvide(c container, p provide, opts ...dig.ProvideOption) error {
constructor := p.Target
if _, ok := constructor.(Option); ok {
return fmt.Errorf("fx.Option should be passed to fx.New directly, "+
"not to fx.Provide: fx.Provide received %v from:\n%+v",
constructor, p.Stack)
}
switch constructor := constructor.(type) {
case annotationError:
// fx.Annotate failed. Turn it into an Fx error.
return fmt.Errorf(
"encountered error while applying annotation using fx.Annotate to %s: %w",
fxreflect.FuncName(constructor.target), constructor.err)
case annotated:
ctor, err := constructor.Build()
if err != nil {
return fmt.Errorf("fx.Provide(%v) from:\n%+vFailed: %w", constructor, p.Stack, err)
}
opts = append(opts, dig.LocationForPC(constructor.FuncPtr))
if err := c.Provide(ctor, opts...); err != nil {
return fmt.Errorf("fx.Provide(%v) from:\n%+vFailed: %w", constructor, p.Stack, err)
}
case Annotated:
ann := constructor
switch {
case len(ann.Group) > 0 && len(ann.Name) > 0:
return fmt.Errorf(
"fx.Annotated may specify only one of Name or Group: received %v from:\n%+v",
ann, p.Stack)
case len(ann.Name) > 0:
opts = append(opts, dig.Name(ann.Name))
case len(ann.Group) > 0:
opts = append(opts, dig.Group(ann.Group))
}
if err := c.Provide(ann.Target, opts...); err != nil {
return fmt.Errorf("fx.Provide(%v) from:\n%+vFailed: %w", ann, p.Stack, err)
}
default:
if reflect.TypeOf(constructor).Kind() == reflect.Func {
ft := reflect.ValueOf(constructor).Type()
for i := 0; i < ft.NumOut(); i++ {
t := ft.Out(i)
if t == reflect.TypeOf(Annotated{}) {
return fmt.Errorf(
"fx.Annotated should be passed to fx.Provide directly, "+
"it should not be returned by the constructor: "+
"fx.Provide received %v from:\n%+v",
fxreflect.FuncName(constructor), p.Stack)
}
}
}
if err := c.Provide(constructor, opts...); err != nil {
return fmt.Errorf("fx.Provide(%v) from:\n%+vFailed: %w", fxreflect.FuncName(constructor), p.Stack, err)
}
}
return nil
}

143
vendor/go.uber.org/fx/replace.go generated vendored Normal file
View File

@@ -0,0 +1,143 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"reflect"
"strings"
"go.uber.org/fx/internal/fxreflect"
)
// Replace provides instantiated values for graph modification as if
// they had been provided using a decorator with fx.Decorate.
// The most specific type of each value (as determined by reflection) is used.
//
// Refer to the documentation on fx.Decorate to see how graph modifications
// work with fx.Module.
//
// This serves a purpose similar to what fx.Supply does for fx.Provide.
//
// For example, given,
//
// var log *zap.Logger = ...
//
// The following two forms are equivalent.
//
// fx.Replace(log)
//
// fx.Decorate(
// func() *zap.Logger {
// return log
// },
// )
//
// Replace panics if a value (or annotation target) is an untyped nil or an error.
//
// # Replace Caveats
//
// As mentioned above, Replace uses the most specific type of the provided
// value. For interface values, this refers to the type of the implementation,
// not the interface. So if you try to replace an io.Writer, fx.Replace will
// use the type of the implementation.
//
// var stderr io.Writer = os.Stderr
// fx.Replace(stderr)
//
// Is equivalent to,
//
// fx.Decorate(func() *os.File { return os.Stderr })
//
// This is typically NOT what you intended. To replace the io.Writer in the
// container with the value above, we need to use the fx.Annotate function with
// the fx.As annotation.
//
// fx.Replace(
// fx.Annotate(os.Stderr, fx.As(new(io.Writer)))
// )
func Replace(values ...interface{}) Option {
decorators := make([]interface{}, len(values)) // one function per value
types := make([]reflect.Type, len(values))
for i, value := range values {
switch value := value.(type) {
case annotated:
var typ reflect.Type
value.Target, typ = newReplaceDecorator(value.Target)
decorators[i] = value
types[i] = typ
default:
decorators[i], types[i] = newReplaceDecorator(value)
}
}
return replaceOption{
Targets: decorators,
Types: types,
Stack: fxreflect.CallerStack(1, 0),
}
}
type replaceOption struct {
Targets []interface{}
Types []reflect.Type // type of value produced by constructor[i]
Stack fxreflect.Stack
}
func (o replaceOption) apply(m *module) {
for i, target := range o.Targets {
m.decorators = append(m.decorators, decorator{
Target: target,
Stack: o.Stack,
IsReplace: true,
ReplaceType: o.Types[i],
})
}
}
func (o replaceOption) String() string {
items := make([]string, 0, len(o.Targets))
for _, typ := range o.Types {
items = append(items, typ.String())
}
return fmt.Sprintf("fx.Replace(%s)", strings.Join(items, ", "))
}
// Returns a function that takes no parameters, and returns the given value.
func newReplaceDecorator(value interface{}) (interface{}, reflect.Type) {
switch value.(type) {
case nil:
panic("untyped nil passed to fx.Replace")
case error:
panic("error value passed to fx.Replace")
}
typ := reflect.TypeOf(value)
returnTypes := []reflect.Type{typ}
returnValues := []reflect.Value{reflect.ValueOf(value)}
ft := reflect.FuncOf([]reflect.Type{}, returnTypes, false)
fv := reflect.MakeFunc(ft, func([]reflect.Value) []reflect.Value {
return returnValues
})
return fv.Interface(), typ
}

94
vendor/go.uber.org/fx/shutdown.go generated vendored Normal file
View File

@@ -0,0 +1,94 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"time"
)
// Shutdowner provides a method that can manually trigger the shutdown of the
// application by sending a signal to all open Done channels. Shutdowner works
// on applications using Run as well as Start, Done, and Stop. The Shutdowner is
// provided to all Fx applications.
type Shutdowner interface {
Shutdown(...ShutdownOption) error
}
// ShutdownOption provides a way to configure properties of the shutdown
// process. Currently, no options have been implemented.
type ShutdownOption interface {
apply(*shutdowner)
}
type exitCodeOption int
func (code exitCodeOption) apply(s *shutdowner) {
s.exitCode = int(code)
}
var _ ShutdownOption = exitCodeOption(0)
// ExitCode is a [ShutdownOption] that may be passed to the Shutdown method of the
// [Shutdowner] interface.
// The given integer exit code will be broadcasted to any receiver waiting
// on a [ShutdownSignal] from the [Wait] method.
func ExitCode(code int) ShutdownOption {
return exitCodeOption(code)
}
type shutdownTimeoutOption time.Duration
func (shutdownTimeoutOption) apply(*shutdowner) {}
var _ ShutdownOption = shutdownTimeoutOption(0)
// ShutdownTimeout is a [ShutdownOption] that allows users to specify a timeout
// for a given call to Shutdown method of the [Shutdowner] interface. As the
// Shutdown method will block while waiting for a signal receiver relay
// goroutine to stop.
//
// Deprecated: This option has no effect. Shutdown is not a blocking operation.
func ShutdownTimeout(timeout time.Duration) ShutdownOption {
return shutdownTimeoutOption(timeout)
}
type shutdowner struct {
app *App
exitCode int
}
// Shutdown broadcasts a signal to all of the application's Done channels
// and begins the Stop process. Applications can be shut down only after they
// have finished starting up.
func (s *shutdowner) Shutdown(opts ...ShutdownOption) error {
for _, opt := range opts {
opt.apply(s)
}
return s.app.receivers.Broadcast(ShutdownSignal{
Signal: _sigTERM,
ExitCode: s.exitCode,
})
}
func (app *App) shutdowner() Shutdowner {
return &shutdowner{app: app}
}

253
vendor/go.uber.org/fx/signal.go generated vendored Normal file
View File

@@ -0,0 +1,253 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPSignalE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"context"
"fmt"
"os"
"os/signal"
"sync"
)
// ShutdownSignal represents a signal to be written to Wait or Done.
// Should a user call the Shutdown method via the Shutdowner interface with
// a provided ExitCode, that exit code will be populated in the ExitCode field.
//
// Should the application receive an operating system signal,
// the Signal field will be populated with the received os.Signal.
type ShutdownSignal struct {
Signal os.Signal
ExitCode int
}
// String will render a ShutdownSignal type as a string suitable for printing.
func (sig ShutdownSignal) String() string {
return fmt.Sprintf("%v", sig.Signal)
}
func newSignalReceivers() signalReceivers {
return signalReceivers{
notify: signal.Notify,
signals: make(chan os.Signal, 1),
}
}
type signalReceivers struct {
// this mutex protects writes and reads of this struct to prevent
// race conditions in a parallel execution pattern
m sync.Mutex
// our os.Signal channel we relay from
signals chan os.Signal
// when written to, will instruct the signal relayer to shutdown
shutdown chan struct{}
// is written to when signal relay has finished shutting down
finished chan struct{}
// this stub allows us to unit test signal relay functionality
notify func(c chan<- os.Signal, sig ...os.Signal)
// last will contain a pointer to the last ShutdownSignal received, or
// nil if none, if a new channel is created by Wait or Done, this last
// signal will be immediately written to, this allows Wait or Done state
// to be read after application stop
last *ShutdownSignal
// contains channels created by Done
done []chan os.Signal
// contains channels created by Wait
wait []chan ShutdownSignal
}
func (recv *signalReceivers) relayer(ctx context.Context) {
defer func() {
recv.finished <- struct{}{}
}()
select {
case <-recv.shutdown:
return
case signal := <-recv.signals:
recv.Broadcast(ShutdownSignal{
Signal: signal,
})
}
}
// running returns true if the the signal relay go-routine is running.
// this method must be invoked under locked mutex to avoid race condition.
func (recv *signalReceivers) running() bool {
return recv.shutdown != nil && recv.finished != nil
}
func (recv *signalReceivers) Start(ctx context.Context) {
recv.m.Lock()
defer recv.m.Unlock()
// if the receiver has already been started; don't start it again
if recv.running() {
return
}
recv.finished = make(chan struct{}, 1)
recv.shutdown = make(chan struct{}, 1)
recv.notify(recv.signals, os.Interrupt, _sigINT, _sigTERM)
go recv.relayer(ctx)
}
func (recv *signalReceivers) Stop(ctx context.Context) error {
recv.m.Lock()
defer recv.m.Unlock()
// if the relayer is not running; return nil error
if !recv.running() {
return nil
}
recv.shutdown <- struct{}{}
select {
case <-ctx.Done():
return ctx.Err()
case <-recv.finished:
close(recv.shutdown)
close(recv.finished)
recv.shutdown = nil
recv.finished = nil
recv.last = nil
return nil
}
}
func (recv *signalReceivers) Done() <-chan os.Signal {
recv.m.Lock()
defer recv.m.Unlock()
ch := make(chan os.Signal, 1)
// If we had received a signal prior to the call of done, send it's
// os.Signal to the new channel.
// However we still want to have the operating system notify signals to this
// channel should the application receive another.
if recv.last != nil {
ch <- recv.last.Signal
}
recv.done = append(recv.done, ch)
return ch
}
func (recv *signalReceivers) Wait() <-chan ShutdownSignal {
recv.m.Lock()
defer recv.m.Unlock()
ch := make(chan ShutdownSignal, 1)
if recv.last != nil {
ch <- *recv.last
}
recv.wait = append(recv.wait, ch)
return ch
}
func (recv *signalReceivers) Broadcast(signal ShutdownSignal) error {
recv.m.Lock()
defer recv.m.Unlock()
recv.last = &signal
channels, unsent := recv.broadcast(
signal,
recv.broadcastDone,
recv.broadcastWait,
)
if unsent != 0 {
return &unsentSignalError{
Signal: signal,
Total: channels,
Unsent: unsent,
}
}
return nil
}
func (recv *signalReceivers) broadcast(
signal ShutdownSignal,
anchors ...func(ShutdownSignal) (int, int),
) (int, int) {
var channels, unsent int
for _, anchor := range anchors {
c, u := anchor(signal)
channels += c
unsent += u
}
return channels, unsent
}
func (recv *signalReceivers) broadcastDone(signal ShutdownSignal) (int, int) {
var unsent int
for _, reader := range recv.done {
select {
case reader <- signal.Signal:
default:
unsent++
}
}
return len(recv.done), unsent
}
func (recv *signalReceivers) broadcastWait(signal ShutdownSignal) (int, int) {
var unsent int
for _, reader := range recv.wait {
select {
case reader <- signal:
default:
unsent++
}
}
return len(recv.wait), unsent
}
type unsentSignalError struct {
Signal ShutdownSignal
Unsent int
Total int
}
func (err *unsentSignalError) Error() string {
return fmt.Sprintf(
"send %v signal: %v/%v channels are blocked",
err.Signal,
err.Unsent,
err.Total,
)
}

151
vendor/go.uber.org/fx/supply.go generated vendored Normal file
View File

@@ -0,0 +1,151 @@
// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
import (
"fmt"
"reflect"
"strings"
"go.uber.org/fx/internal/fxreflect"
)
// Supply provides instantiated values for dependency injection as if
// they had been provided using a constructor that simply returns them.
// The most specific type of each value (as determined by reflection) is used.
//
// This serves a purpose similar to what fx.Replace does for fx.Decorate.
//
// For example, given:
//
// type (
// TypeA struct{}
// TypeB struct{}
// TypeC struct{}
// )
//
// var a, b, c = &TypeA{}, TypeB{}, &TypeC{}
//
// The following two forms are equivalent:
//
// fx.Supply(a, b, fx.Annotated{Target: c})
//
// fx.Provide(
// func() *TypeA { return a },
// func() TypeB { return b },
// fx.Annotated{Target: func() *TypeC { return c }},
// )
//
// Supply panics if a value (or annotation target) is an untyped nil or an error.
//
// # Supply Caveats
//
// As mentioned above, Supply uses the most specific type of the provided
// value. For interface values, this refers to the type of the implementation,
// not the interface. So if you supply an http.Handler, fx.Supply will use the
// type of the implementation.
//
// var handler http.Handler = http.HandlerFunc(f)
// fx.Supply(handler)
//
// Is equivalent to,
//
// fx.Provide(func() http.HandlerFunc { return f })
//
// This is typically NOT what you intended. To supply the handler above as an
// http.Handler, we need to use the fx.Annotate function with the fx.As
// annotation.
//
// fx.Supply(
// fx.Annotate(handler, fx.As(new(http.Handler))),
// )
func Supply(values ...interface{}) Option {
constructors := make([]interface{}, len(values)) // one function per value
types := make([]reflect.Type, len(values))
for i, value := range values {
switch value := value.(type) {
case annotated:
var typ reflect.Type
value.Target, typ = newSupplyConstructor(value.Target)
constructors[i] = value
types[i] = typ
case Annotated:
var typ reflect.Type
value.Target, typ = newSupplyConstructor(value.Target)
constructors[i] = value
types[i] = typ
default:
constructors[i], types[i] = newSupplyConstructor(value)
}
}
return supplyOption{
Targets: constructors,
Types: types,
Stack: fxreflect.CallerStack(1, 0),
}
}
type supplyOption struct {
Targets []interface{}
Types []reflect.Type // type of value produced by constructor[i]
Stack fxreflect.Stack
}
func (o supplyOption) apply(m *module) {
for i, target := range o.Targets {
m.provides = append(m.provides, provide{
Target: target,
Stack: o.Stack,
IsSupply: true,
SupplyType: o.Types[i],
})
}
}
func (o supplyOption) String() string {
items := make([]string, 0, len(o.Targets))
for _, typ := range o.Types {
items = append(items, typ.String())
}
return fmt.Sprintf("fx.Supply(%s)", strings.Join(items, ", "))
}
// Returns a function that takes no parameters, and returns the given value.
func newSupplyConstructor(value interface{}) (interface{}, reflect.Type) {
switch value.(type) {
case nil:
panic("untyped nil passed to fx.Supply")
case error:
panic("error value passed to fx.Supply")
}
typ := reflect.TypeOf(value)
returnTypes := []reflect.Type{typ}
returnValues := []reflect.Value{reflect.ValueOf(value)}
ft := reflect.FuncOf([]reflect.Type{}, returnTypes, false)
fv := reflect.MakeFunc(ft, func([]reflect.Value) []reflect.Value {
return returnValues
})
return fv.Interface(), typ
}

24
vendor/go.uber.org/fx/version.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package fx
// Version is exported for runtime compatibility checks.
const Version = "1.20.1"

12
vendor/go.uber.org/mock/AUTHORS generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# This is the official list of GoMock authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Alex Reece <awreece@gmail.com>
Google Inc.

37
vendor/go.uber.org/mock/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,37 @@
# This is the official list of people who can contribute (and typically
# have contributed) code to the gomock repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# The submission process automatically checks to make sure
# that people submitting code are listed in this file (by email address).
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# http://code.google.com/legal/individual-cla-v1.0.html
# http://code.google.com/legal/corporate-cla-v1.0.html
#
# The agreement for individuals can be filled out on the web.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
# Names should be added to this file like so:
# Name <email address>
#
# An entry with two email addresses specifies that the
# first address should be used in the submit logs and
# that the second address should be recognized as the
# same person when interacting with Rietveld.
# Please keep the list sorted.
Aaron Jacobs <jacobsa@google.com> <aaronjjacobs@gmail.com>
Alex Reece <awreece@gmail.com>
David Symonds <dsymonds@golang.org>
Ryan Barrett <ryanb@google.com>

202
vendor/go.uber.org/mock/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

116
vendor/go.uber.org/mock/mockgen/generic_go118.go generated vendored Normal file
View File

@@ -0,0 +1,116 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build go1.18
// +build go1.18
package main
import (
"fmt"
"go/ast"
"strings"
"go.uber.org/mock/mockgen/model"
)
func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field {
if ts == nil || ts.TypeParams == nil {
return nil
}
return ts.TypeParams.List
}
func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]model.Type) (model.Type, error) {
switch v := typ.(type) {
case *ast.IndexExpr:
m, err := p.parseType(pkg, v.X, tps)
if err != nil {
return nil, err
}
nm, ok := m.(*model.NamedType)
if !ok {
return m, nil
}
t, err := p.parseType(pkg, v.Index, tps)
if err != nil {
return nil, err
}
nm.TypeParams = &model.TypeParametersType{TypeParameters: []model.Type{t}}
return m, nil
case *ast.IndexListExpr:
m, err := p.parseType(pkg, v.X, tps)
if err != nil {
return nil, err
}
nm, ok := m.(*model.NamedType)
if !ok {
return m, nil
}
var ts []model.Type
for _, expr := range v.Indices {
t, err := p.parseType(pkg, expr, tps)
if err != nil {
return nil, err
}
ts = append(ts, t)
}
nm.TypeParams = &model.TypeParametersType{TypeParameters: ts}
return m, nil
}
return nil, nil
}
func getIdentTypeParams(decl any) string {
if decl == nil {
return ""
}
ts, ok := decl.(*ast.TypeSpec)
if !ok {
return ""
}
if ts.TypeParams == nil || len(ts.TypeParams.List) == 0 {
return ""
}
var sb strings.Builder
sb.WriteString("[")
for i, v := range ts.TypeParams.List {
if i != 0 {
sb.WriteString(", ")
}
sb.WriteString(v.Names[0].Name)
}
sb.WriteString("]")
return sb.String()
}
func (p *fileParser) parseGenericMethod(field *ast.Field, it *namedInterface, iface *model.Interface, pkg string, tps map[string]model.Type) ([]*model.Method, error) {
var indices []ast.Expr
var typ ast.Expr
switch v := field.Type.(type) {
case *ast.IndexExpr:
indices = []ast.Expr{v.Index}
typ = v.X
case *ast.IndexListExpr:
indices = v.Indices
typ = v.X
default:
return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type)
}
nf := &ast.Field{
Doc: field.Comment,
Names: field.Names,
Type: typ,
Tag: field.Tag,
Comment: field.Comment,
}
it.embeddedInstTypeParams = indices
return p.parseMethod(nf, it, iface, pkg, tps)
}

41
vendor/go.uber.org/mock/mockgen/generic_notgo118.go generated vendored Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !go1.18
// +build !go1.18
package main
import (
"fmt"
"go/ast"
"go.uber.org/mock/mockgen/model"
)
func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field {
return nil
}
func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]model.Type) (model.Type, error) {
return nil, nil
}
func getIdentTypeParams(decl any) string {
return ""
}
func (p *fileParser) parseGenericMethod(field *ast.Field, it *namedInterface, iface *model.Interface, pkg string, tps map[string]model.Type) ([]*model.Method, error) {
return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type)
}

870
vendor/go.uber.org/mock/mockgen/mockgen.go generated vendored Normal file
View File

@@ -0,0 +1,870 @@
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// MockGen generates mock implementations of Go interfaces.
package main
// TODO: This does not support recursive embedded interfaces.
// TODO: This does not support embedding package-local interfaces in a separate file.
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
"go/token"
"io"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
"unicode"
"golang.org/x/mod/modfile"
toolsimports "golang.org/x/tools/imports"
"go.uber.org/mock/mockgen/model"
)
const (
gomockImportPath = "go.uber.org/mock/gomock"
)
var (
version = ""
commit = "none"
date = "unknown"
)
var (
source = flag.String("source", "", "(source mode) Input Go source file; enables source mode.")
destination = flag.String("destination", "", "Output file; defaults to stdout.")
mockNames = flag.String("mock_names", "", "Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix.")
packageOut = flag.String("package", "", "Package of the generated code; defaults to the package of the input with a 'mock_' prefix.")
selfPackage = flag.String("self_package", "", "The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.")
writePkgComment = flag.Bool("write_package_comment", true, "Writes package documentation comment (godoc) if true.")
writeSourceComment = flag.Bool("write_source_comment", true, "Writes original file (source mode) or interface names (reflect mode) comment if true.")
writeGenerateDirective = flag.Bool("write_generate_directive", false, "Add //go:generate directive to regenerate the mock")
copyrightFile = flag.String("copyright_file", "", "Copyright file used to add copyright header")
typed = flag.Bool("typed", false, "Generate Type-safe 'Return', 'Do', 'DoAndReturn' function")
imports = flag.String("imports", "", "(source mode) Comma-separated name=path pairs of explicit imports to use.")
auxFiles = flag.String("aux_files", "", "(source mode) Comma-separated pkg=path pairs of auxiliary Go source files.")
excludeInterfaces = flag.String("exclude_interfaces", "", "Comma-separated names of interfaces to be excluded")
debugParser = flag.Bool("debug_parser", false, "Print out parser results only.")
showVersion = flag.Bool("version", false, "Print version.")
)
func main() {
flag.Usage = usage
flag.Parse()
if *showVersion {
printVersion()
return
}
var pkg *model.Package
var err error
var packageName string
if *source != "" {
pkg, err = sourceMode(*source)
} else {
if flag.NArg() != 2 {
usage()
log.Fatal("Expected exactly two arguments")
}
packageName = flag.Arg(0)
interfaces := strings.Split(flag.Arg(1), ",")
if packageName == "." {
dir, err := os.Getwd()
if err != nil {
log.Fatalf("Get current directory failed: %v", err)
}
packageName, err = packageNameOfDir(dir)
if err != nil {
log.Fatalf("Parse package name failed: %v", err)
}
}
pkg, err = reflectMode(packageName, interfaces)
}
if err != nil {
log.Fatalf("Loading input failed: %v", err)
}
if *debugParser {
pkg.Print(os.Stdout)
return
}
outputPackageName := *packageOut
if outputPackageName == "" {
// pkg.Name in reflect mode is the base name of the import path,
// which might have characters that are illegal to have in package names.
outputPackageName = "mock_" + sanitize(pkg.Name)
}
// outputPackagePath represents the fully qualified name of the package of
// the generated code. Its purposes are to prevent the module from importing
// itself and to prevent qualifying type names that come from its own
// package (i.e. if there is a type called X then we want to print "X" not
// "package.X" since "package" is this package). This can happen if the mock
// is output into an already existing package.
outputPackagePath := *selfPackage
if outputPackagePath == "" && *destination != "" {
dstPath, err := filepath.Abs(filepath.Dir(*destination))
if err == nil {
pkgPath, err := parsePackageImport(dstPath)
if err == nil {
outputPackagePath = pkgPath
} else {
log.Println("Unable to infer -self_package from destination file path:", err)
}
} else {
log.Println("Unable to determine destination file path:", err)
}
}
g := new(generator)
if *source != "" {
g.filename = *source
} else {
g.srcPackage = packageName
g.srcInterfaces = flag.Arg(1)
}
g.destination = *destination
if *mockNames != "" {
g.mockNames = parseMockNames(*mockNames)
}
if *copyrightFile != "" {
header, err := os.ReadFile(*copyrightFile)
if err != nil {
log.Fatalf("Failed reading copyright file: %v", err)
}
g.copyrightHeader = string(header)
}
if err := g.Generate(pkg, outputPackageName, outputPackagePath); err != nil {
log.Fatalf("Failed generating mock: %v", err)
}
output := g.Output()
dst := os.Stdout
if len(*destination) > 0 {
if err := os.MkdirAll(filepath.Dir(*destination), os.ModePerm); err != nil {
log.Fatalf("Unable to create directory: %v", err)
}
existing, err := os.ReadFile(*destination)
if err != nil && !errors.Is(err, os.ErrNotExist) {
log.Fatalf("Failed reading pre-exiting destination file: %v", err)
}
if len(existing) == len(output) && bytes.Equal(existing, output) {
return
}
f, err := os.Create(*destination)
if err != nil {
log.Fatalf("Failed opening destination file: %v", err)
}
defer f.Close()
dst = f
}
if _, err := dst.Write(output); err != nil {
log.Fatalf("Failed writing to destination: %v", err)
}
}
func parseMockNames(names string) map[string]string {
mocksMap := make(map[string]string)
for _, kv := range strings.Split(names, ",") {
parts := strings.SplitN(kv, "=", 2)
if len(parts) != 2 || parts[1] == "" {
log.Fatalf("bad mock names spec: %v", kv)
}
mocksMap[parts[0]] = parts[1]
}
return mocksMap
}
func parseExcludeInterfaces(names string) map[string]struct{} {
splitNames := strings.Split(names, ",")
namesSet := make(map[string]struct{}, len(splitNames))
for _, name := range splitNames {
if name == "" {
continue
}
namesSet[name] = struct{}{}
}
if len(namesSet) == 0 {
return nil
}
return namesSet
}
func usage() {
_, _ = io.WriteString(os.Stderr, usageText)
flag.PrintDefaults()
}
const usageText = `mockgen has two modes of operation: source and reflect.
Source mode generates mock interfaces from a source file.
It is enabled by using the -source flag. Other flags that
may be useful in this mode are -imports and -aux_files.
Example:
mockgen -source=foo.go [other options]
Reflect mode generates mock interfaces by building a program
that uses reflection to understand interfaces. It is enabled
by passing two non-flag arguments: an import path, and a
comma-separated list of symbols.
Example:
mockgen database/sql/driver Conn,Driver
`
type generator struct {
buf bytes.Buffer
indent string
mockNames map[string]string // may be empty
filename string // may be empty
destination string // may be empty
srcPackage, srcInterfaces string // may be empty
copyrightHeader string
packageMap map[string]string // map from import path to package name
}
func (g *generator) p(format string, args ...any) {
fmt.Fprintf(&g.buf, g.indent+format+"\n", args...)
}
func (g *generator) in() {
g.indent += "\t"
}
func (g *generator) out() {
if len(g.indent) > 0 {
g.indent = g.indent[0 : len(g.indent)-1]
}
}
// sanitize cleans up a string to make a suitable package name.
func sanitize(s string) string {
t := ""
for _, r := range s {
if t == "" {
if unicode.IsLetter(r) || r == '_' {
t += string(r)
continue
}
} else {
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
t += string(r)
continue
}
}
t += "_"
}
if t == "_" {
t = "x"
}
return t
}
func (g *generator) Generate(pkg *model.Package, outputPkgName string, outputPackagePath string) error {
if outputPkgName != pkg.Name && *selfPackage == "" {
// reset outputPackagePath if it's not passed in through -self_package
outputPackagePath = ""
}
if g.copyrightHeader != "" {
lines := strings.Split(g.copyrightHeader, "\n")
for _, line := range lines {
g.p("// %s", line)
}
g.p("")
}
g.p("// Code generated by MockGen. DO NOT EDIT.")
if *writeSourceComment {
if g.filename != "" {
g.p("// Source: %v", g.filename)
} else {
g.p("// Source: %v (interfaces: %v)", g.srcPackage, g.srcInterfaces)
}
}
g.p("//")
g.p("// Generated by this command:")
// only log the name of the executable, not the full path
g.p("// %v", strings.Join(append([]string{filepath.Base(os.Args[0])}, os.Args[1:]...), " "))
// Get all required imports, and generate unique names for them all.
im := pkg.Imports()
im[gomockImportPath] = true
// Only import reflect if it's used. We only use reflect in mocked methods
// so only import if any of the mocked interfaces have methods.
for _, intf := range pkg.Interfaces {
if len(intf.Methods) > 0 {
im["reflect"] = true
break
}
}
// Sort keys to make import alias generation predictable
sortedPaths := make([]string, len(im))
x := 0
for pth := range im {
sortedPaths[x] = pth
x++
}
sort.Strings(sortedPaths)
packagesName := createPackageMap(sortedPaths)
definedImports := make(map[string]string, len(im))
if *imports != "" {
for _, kv := range strings.Split(*imports, ",") {
eq := strings.Index(kv, "=")
if k, v := kv[:eq], kv[eq+1:]; k != "." {
definedImports[v] = k
}
}
}
g.packageMap = make(map[string]string, len(im))
localNames := make(map[string]bool, len(im))
for _, pth := range sortedPaths {
base, ok := packagesName[pth]
if !ok {
base = sanitize(path.Base(pth))
}
// Local names for an imported package can usually be the basename of the import path.
// A couple of situations don't permit that, such as duplicate local names
// (e.g. importing "html/template" and "text/template"), or where the basename is
// a keyword (e.g. "foo/case") or when defining a name for that by using the -imports flag.
// try base0, base1, ...
pkgName := base
if _, ok := definedImports[base]; ok {
pkgName = definedImports[base]
}
i := 0
for localNames[pkgName] || token.Lookup(pkgName).IsKeyword() {
pkgName = base + strconv.Itoa(i)
i++
}
// Avoid importing package if source pkg == output pkg
if pth == pkg.PkgPath && outputPackagePath == pkg.PkgPath {
continue
}
g.packageMap[pth] = pkgName
localNames[pkgName] = true
}
if *writePkgComment {
g.p("// Package %v is a generated GoMock package.", outputPkgName)
}
g.p("package %v", outputPkgName)
g.p("")
g.p("import (")
g.in()
for pkgPath, pkgName := range g.packageMap {
if pkgPath == outputPackagePath {
continue
}
g.p("%v %q", pkgName, pkgPath)
}
for _, pkgPath := range pkg.DotImports {
g.p(". %q", pkgPath)
}
g.out()
g.p(")")
if *writeGenerateDirective {
g.p("//go:generate %v", strings.Join(os.Args, " "))
}
for _, intf := range pkg.Interfaces {
if err := g.GenerateMockInterface(intf, outputPackagePath); err != nil {
return err
}
}
return nil
}
// The name of the mock type to use for the given interface identifier.
func (g *generator) mockName(typeName string) string {
if mockName, ok := g.mockNames[typeName]; ok {
return mockName
}
return "Mock" + typeName
}
// formattedTypeParams returns a long and short form of type param info used for
// printing. If analyzing a interface with type param [I any, O any] the result
// will be:
// "[I any, O any]", "[I, O]"
func (g *generator) formattedTypeParams(it *model.Interface, pkgOverride string) (string, string) {
if len(it.TypeParams) == 0 {
return "", ""
}
var long, short strings.Builder
long.WriteString("[")
short.WriteString("[")
for i, v := range it.TypeParams {
if i != 0 {
long.WriteString(", ")
short.WriteString(", ")
}
long.WriteString(v.Name)
short.WriteString(v.Name)
long.WriteString(fmt.Sprintf(" %s", v.Type.String(g.packageMap, pkgOverride)))
}
long.WriteString("]")
short.WriteString("]")
return long.String(), short.String()
}
func (g *generator) GenerateMockInterface(intf *model.Interface, outputPackagePath string) error {
mockType := g.mockName(intf.Name)
longTp, shortTp := g.formattedTypeParams(intf, outputPackagePath)
g.p("")
g.p("// %v is a mock of %v interface.", mockType, intf.Name)
g.p("type %v%v struct {", mockType, longTp)
g.in()
g.p("ctrl *gomock.Controller")
g.p("recorder *%vMockRecorder%v", mockType, shortTp)
g.out()
g.p("}")
g.p("")
g.p("// %vMockRecorder is the mock recorder for %v.", mockType, mockType)
g.p("type %vMockRecorder%v struct {", mockType, longTp)
g.in()
g.p("mock *%v%v", mockType, shortTp)
g.out()
g.p("}")
g.p("")
g.p("// New%v creates a new mock instance.", mockType)
g.p("func New%v%v(ctrl *gomock.Controller) *%v%v {", mockType, longTp, mockType, shortTp)
g.in()
g.p("mock := &%v%v{ctrl: ctrl}", mockType, shortTp)
g.p("mock.recorder = &%vMockRecorder%v{mock}", mockType, shortTp)
g.p("return mock")
g.out()
g.p("}")
g.p("")
// XXX: possible name collision here if someone has EXPECT in their interface.
g.p("// EXPECT returns an object that allows the caller to indicate expected use.")
g.p("func (m *%v%v) EXPECT() *%vMockRecorder%v {", mockType, shortTp, mockType, shortTp)
g.in()
g.p("return m.recorder")
g.out()
g.p("}")
g.GenerateMockMethods(mockType, intf, outputPackagePath, longTp, shortTp, *typed)
return nil
}
type byMethodName []*model.Method
func (b byMethodName) Len() int { return len(b) }
func (b byMethodName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byMethodName) Less(i, j int) bool { return b[i].Name < b[j].Name }
func (g *generator) GenerateMockMethods(mockType string, intf *model.Interface, pkgOverride, longTp, shortTp string, typed bool) {
sort.Sort(byMethodName(intf.Methods))
for _, m := range intf.Methods {
g.p("")
_ = g.GenerateMockMethod(mockType, m, pkgOverride, shortTp)
g.p("")
_ = g.GenerateMockRecorderMethod(intf, mockType, m, shortTp, typed)
if typed {
g.p("")
_ = g.GenerateMockReturnCallMethod(intf, m, pkgOverride, longTp, shortTp)
}
}
}
func makeArgString(argNames, argTypes []string) string {
args := make([]string, len(argNames))
for i, name := range argNames {
// specify the type only once for consecutive args of the same type
if i+1 < len(argTypes) && argTypes[i] == argTypes[i+1] {
args[i] = name
} else {
args[i] = name + " " + argTypes[i]
}
}
return strings.Join(args, ", ")
}
// GenerateMockMethod generates a mock method implementation.
// If non-empty, pkgOverride is the package in which unqualified types reside.
func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOverride, shortTp string) error {
argNames := g.getArgNames(m, true /* in */)
argTypes := g.getArgTypes(m, pkgOverride, true /* in */)
argString := makeArgString(argNames, argTypes)
rets := make([]string, len(m.Out))
for i, p := range m.Out {
rets[i] = p.Type.String(g.packageMap, pkgOverride)
}
retString := strings.Join(rets, ", ")
if len(rets) > 1 {
retString = "(" + retString + ")"
}
if retString != "" {
retString = " " + retString
}
ia := newIdentifierAllocator(argNames)
idRecv := ia.allocateIdentifier("m")
g.p("// %v mocks base method.", m.Name)
g.p("func (%v *%v%v) %v(%v)%v {", idRecv, mockType, shortTp, m.Name, argString, retString)
g.in()
g.p("%s.ctrl.T.Helper()", idRecv)
var callArgs string
if m.Variadic == nil {
if len(argNames) > 0 {
callArgs = ", " + strings.Join(argNames, ", ")
}
} else {
// Non-trivial. The generated code must build a []any,
// but the variadic argument may be any type.
idVarArgs := ia.allocateIdentifier("varargs")
idVArg := ia.allocateIdentifier("a")
g.p("%s := []any{%s}", idVarArgs, strings.Join(argNames[:len(argNames)-1], ", "))
g.p("for _, %s := range %s {", idVArg, argNames[len(argNames)-1])
g.in()
g.p("%s = append(%s, %s)", idVarArgs, idVarArgs, idVArg)
g.out()
g.p("}")
callArgs = ", " + idVarArgs + "..."
}
if len(m.Out) == 0 {
g.p(`%v.ctrl.Call(%v, %q%v)`, idRecv, idRecv, m.Name, callArgs)
} else {
idRet := ia.allocateIdentifier("ret")
g.p(`%v := %v.ctrl.Call(%v, %q%v)`, idRet, idRecv, idRecv, m.Name, callArgs)
// Go does not allow "naked" type assertions on nil values, so we use the two-value form here.
// The value of that is either (x.(T), true) or (Z, false), where Z is the zero value for T.
// Happily, this coincides with the semantics we want here.
retNames := make([]string, len(rets))
for i, t := range rets {
retNames[i] = ia.allocateIdentifier(fmt.Sprintf("ret%d", i))
g.p("%s, _ := %s[%d].(%s)", retNames[i], idRet, i, t)
}
g.p("return " + strings.Join(retNames, ", "))
}
g.out()
g.p("}")
return nil
}
func (g *generator) GenerateMockRecorderMethod(intf *model.Interface, mockType string, m *model.Method, shortTp string, typed bool) error {
argNames := g.getArgNames(m, true)
var argString string
if m.Variadic == nil {
argString = strings.Join(argNames, ", ")
} else {
argString = strings.Join(argNames[:len(argNames)-1], ", ")
}
if argString != "" {
argString += " any"
}
if m.Variadic != nil {
if argString != "" {
argString += ", "
}
argString += fmt.Sprintf("%s ...any", argNames[len(argNames)-1])
}
ia := newIdentifierAllocator(argNames)
idRecv := ia.allocateIdentifier("mr")
g.p("// %v indicates an expected call of %v.", m.Name, m.Name)
if typed {
g.p("func (%s *%vMockRecorder%v) %v(%v) *%s%sCall%s {", idRecv, mockType, shortTp, m.Name, argString, intf.Name, m.Name, shortTp)
} else {
g.p("func (%s *%vMockRecorder%v) %v(%v) *gomock.Call {", idRecv, mockType, shortTp, m.Name, argString)
}
g.in()
g.p("%s.mock.ctrl.T.Helper()", idRecv)
var callArgs string
if m.Variadic == nil {
if len(argNames) > 0 {
callArgs = ", " + strings.Join(argNames, ", ")
}
} else {
if len(argNames) == 1 {
// Easy: just use ... to push the arguments through.
callArgs = ", " + argNames[0] + "..."
} else {
// Hard: create a temporary slice.
idVarArgs := ia.allocateIdentifier("varargs")
g.p("%s := append([]any{%s}, %s...)",
idVarArgs,
strings.Join(argNames[:len(argNames)-1], ", "),
argNames[len(argNames)-1])
callArgs = ", " + idVarArgs + "..."
}
}
if typed {
g.p(`call := %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, shortTp, m.Name, callArgs)
g.p(`return &%s%sCall%s{Call: call}`, intf.Name, m.Name, shortTp)
} else {
g.p(`return %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, shortTp, m.Name, callArgs)
}
g.out()
g.p("}")
return nil
}
func (g *generator) GenerateMockReturnCallMethod(intf *model.Interface, m *model.Method, pkgOverride, longTp, shortTp string) error {
argNames := g.getArgNames(m, true /* in */)
retNames := g.getArgNames(m, false /* out */)
argTypes := g.getArgTypes(m, pkgOverride, true /* in */)
retTypes := g.getArgTypes(m, pkgOverride, false /* out */)
argString := strings.Join(argTypes, ", ")
rets := make([]string, len(m.Out))
for i, p := range m.Out {
rets[i] = p.Type.String(g.packageMap, pkgOverride)
}
var retString string
switch {
case len(rets) == 1:
retString = " " + rets[0]
case len(rets) > 1:
retString = " (" + strings.Join(rets, ", ") + ")"
}
ia := newIdentifierAllocator(argNames)
idRecv := ia.allocateIdentifier("c")
recvStructName := intf.Name + m.Name
g.p("// %s%sCall wrap *gomock.Call", intf.Name, m.Name)
g.p("type %s%sCall%s struct{", intf.Name, m.Name, longTp)
g.in()
g.p("*gomock.Call")
g.out()
g.p("}")
g.p("// Return rewrite *gomock.Call.Return")
g.p("func (%s *%sCall%s) Return(%v) *%sCall%s {", idRecv, recvStructName, shortTp, makeArgString(retNames, retTypes), recvStructName, shortTp)
g.in()
var retArgs string
if len(retNames) > 0 {
retArgs = strings.Join(retNames, ", ")
}
g.p(`%s.Call = %v.Call.Return(%v)`, idRecv, idRecv, retArgs)
g.p("return %s", idRecv)
g.out()
g.p("}")
g.p("// Do rewrite *gomock.Call.Do")
g.p("func (%s *%sCall%s) Do(f func(%v)%v) *%sCall%s {", idRecv, recvStructName, shortTp, argString, retString, recvStructName, shortTp)
g.in()
g.p(`%s.Call = %v.Call.Do(f)`, idRecv, idRecv)
g.p("return %s", idRecv)
g.out()
g.p("}")
g.p("// DoAndReturn rewrite *gomock.Call.DoAndReturn")
g.p("func (%s *%sCall%s) DoAndReturn(f func(%v)%v) *%sCall%s {", idRecv, recvStructName, shortTp, argString, retString, recvStructName, shortTp)
g.in()
g.p(`%s.Call = %v.Call.DoAndReturn(f)`, idRecv, idRecv)
g.p("return %s", idRecv)
g.out()
g.p("}")
return nil
}
func (g *generator) getArgNames(m *model.Method, in bool) []string {
var params []*model.Parameter
if in {
params = m.In
} else {
params = m.Out
}
argNames := make([]string, len(params))
for i, p := range params {
name := p.Name
if name == "" || name == "_" {
name = fmt.Sprintf("arg%d", i)
}
argNames[i] = name
}
if m.Variadic != nil && in {
name := m.Variadic.Name
if name == "" {
name = fmt.Sprintf("arg%d", len(params))
}
argNames = append(argNames, name)
}
return argNames
}
func (g *generator) getArgTypes(m *model.Method, pkgOverride string, in bool) []string {
var params []*model.Parameter
if in {
params = m.In
} else {
params = m.Out
}
argTypes := make([]string, len(params))
for i, p := range params {
argTypes[i] = p.Type.String(g.packageMap, pkgOverride)
}
if m.Variadic != nil {
argTypes = append(argTypes, "..."+m.Variadic.Type.String(g.packageMap, pkgOverride))
}
return argTypes
}
type identifierAllocator map[string]struct{}
func newIdentifierAllocator(taken []string) identifierAllocator {
a := make(identifierAllocator, len(taken))
for _, s := range taken {
a[s] = struct{}{}
}
return a
}
func (o identifierAllocator) allocateIdentifier(want string) string {
id := want
for i := 2; ; i++ {
if _, ok := o[id]; !ok {
o[id] = struct{}{}
return id
}
id = want + "_" + strconv.Itoa(i)
}
}
// Output returns the generator's output, formatted in the standard Go style.
func (g *generator) Output() []byte {
src, err := toolsimports.Process(g.destination, g.buf.Bytes(), nil)
if err != nil {
log.Fatalf("Failed to format generated source code: %s\n%s", err, g.buf.String())
}
return src
}
// createPackageMap returns a map of import path to package name
// for specified importPaths.
func createPackageMap(importPaths []string) map[string]string {
var pkg struct {
Name string
ImportPath string
}
pkgMap := make(map[string]string)
b := bytes.NewBuffer(nil)
args := []string{"list", "-json"}
args = append(args, importPaths...)
cmd := exec.Command("go", args...)
cmd.Stdout = b
cmd.Run()
dec := json.NewDecoder(b)
for dec.More() {
err := dec.Decode(&pkg)
if err != nil {
log.Printf("failed to decode 'go list' output: %v", err)
continue
}
pkgMap[pkg.ImportPath] = pkg.Name
}
return pkgMap
}
func printVersion() {
if version != "" {
fmt.Printf("v%s\nCommit: %s\nDate: %s\n", version, commit, date)
} else {
printModuleVersion()
}
}
// parseImportPackage get package import path via source file
// an alternative implementation is to use:
// cfg := &packages.Config{Mode: packages.NeedName, Tests: true, Dir: srcDir}
// pkgs, err := packages.Load(cfg, "file="+source)
// However, it will call "go list" and slow down the performance
func parsePackageImport(srcDir string) (string, error) {
moduleMode := os.Getenv("GO111MODULE")
// trying to find the module
if moduleMode != "off" {
currentDir := srcDir
for {
dat, err := os.ReadFile(filepath.Join(currentDir, "go.mod"))
if os.IsNotExist(err) {
if currentDir == filepath.Dir(currentDir) {
// at the root
break
}
currentDir = filepath.Dir(currentDir)
continue
} else if err != nil {
return "", err
}
modulePath := modfile.ModulePath(dat)
return filepath.ToSlash(filepath.Join(modulePath, strings.TrimPrefix(srcDir, currentDir))), nil
}
}
// fall back to GOPATH mode
goPaths := os.Getenv("GOPATH")
if goPaths == "" {
return "", fmt.Errorf("GOPATH is not set")
}
goPathList := strings.Split(goPaths, string(os.PathListSeparator))
for _, goPath := range goPathList {
sourceRoot := filepath.Join(goPath, "src") + string(os.PathSeparator)
if strings.HasPrefix(srcDir, sourceRoot) {
return filepath.ToSlash(strings.TrimPrefix(srcDir, sourceRoot)), nil
}
}
return "", errOutsideGoPath
}

533
vendor/go.uber.org/mock/mockgen/model/model.go generated vendored Normal file
View File

@@ -0,0 +1,533 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package model contains the data model necessary for generating mock implementations.
package model
import (
"encoding/gob"
"fmt"
"io"
"reflect"
"strings"
)
// pkgPath is the importable path for package model
const pkgPath = "go.uber.org/mock/mockgen/model"
// Package is a Go package. It may be a subset.
type Package struct {
Name string
PkgPath string
Interfaces []*Interface
DotImports []string
}
// Print writes the package name and its exported interfaces.
func (pkg *Package) Print(w io.Writer) {
_, _ = fmt.Fprintf(w, "package %s\n", pkg.Name)
for _, intf := range pkg.Interfaces {
intf.Print(w)
}
}
// Imports returns the imports needed by the Package as a set of import paths.
func (pkg *Package) Imports() map[string]bool {
im := make(map[string]bool)
for _, intf := range pkg.Interfaces {
intf.addImports(im)
for _, tp := range intf.TypeParams {
tp.Type.addImports(im)
}
}
return im
}
// Interface is a Go interface.
type Interface struct {
Name string
Methods []*Method
TypeParams []*Parameter
}
// Print writes the interface name and its methods.
func (intf *Interface) Print(w io.Writer) {
_, _ = fmt.Fprintf(w, "interface %s\n", intf.Name)
for _, m := range intf.Methods {
m.Print(w)
}
}
func (intf *Interface) addImports(im map[string]bool) {
for _, m := range intf.Methods {
m.addImports(im)
}
}
// AddMethod adds a new method, de-duplicating by method name.
func (intf *Interface) AddMethod(m *Method) {
for _, me := range intf.Methods {
if me.Name == m.Name {
return
}
}
intf.Methods = append(intf.Methods, m)
}
// Method is a single method of an interface.
type Method struct {
Name string
In, Out []*Parameter
Variadic *Parameter // may be nil
}
// Print writes the method name and its signature.
func (m *Method) Print(w io.Writer) {
_, _ = fmt.Fprintf(w, " - method %s\n", m.Name)
if len(m.In) > 0 {
_, _ = fmt.Fprintf(w, " in:\n")
for _, p := range m.In {
p.Print(w)
}
}
if m.Variadic != nil {
_, _ = fmt.Fprintf(w, " ...:\n")
m.Variadic.Print(w)
}
if len(m.Out) > 0 {
_, _ = fmt.Fprintf(w, " out:\n")
for _, p := range m.Out {
p.Print(w)
}
}
}
func (m *Method) addImports(im map[string]bool) {
for _, p := range m.In {
p.Type.addImports(im)
}
if m.Variadic != nil {
m.Variadic.Type.addImports(im)
}
for _, p := range m.Out {
p.Type.addImports(im)
}
}
// Parameter is an argument or return parameter of a method.
type Parameter struct {
Name string // may be empty
Type Type
}
// Print writes a method parameter.
func (p *Parameter) Print(w io.Writer) {
n := p.Name
if n == "" {
n = `""`
}
_, _ = fmt.Fprintf(w, " - %v: %v\n", n, p.Type.String(nil, ""))
}
// Type is a Go type.
type Type interface {
String(pm map[string]string, pkgOverride string) string
addImports(im map[string]bool)
}
func init() {
// Call gob.RegisterName with pkgPath as prefix to avoid conflicting with
// github.com/golang/mock/mockgen/model 's registration.
gob.RegisterName(pkgPath+".ArrayType", &ArrayType{})
gob.RegisterName(pkgPath+".ChanType", &ChanType{})
gob.RegisterName(pkgPath+".FuncType", &FuncType{})
gob.RegisterName(pkgPath+".MapType", &MapType{})
gob.RegisterName(pkgPath+".NamedType", &NamedType{})
gob.RegisterName(pkgPath+".PointerType", &PointerType{})
// Call gob.RegisterName to make sure it has the consistent name registered
// for both gob decoder and encoder.
//
// For a non-pointer type, gob.Register will try to get package full path by
// calling rt.PkgPath() for a name to register. If your project has vendor
// directory, it is possible that PkgPath will get a path like this:
// ../../../vendor/go.uber.org/mock/mockgen/model
gob.RegisterName(pkgPath+".PredeclaredType", PredeclaredType(""))
}
// ArrayType is an array or slice type.
type ArrayType struct {
Len int // -1 for slices, >= 0 for arrays
Type Type
}
func (at *ArrayType) String(pm map[string]string, pkgOverride string) string {
s := "[]"
if at.Len > -1 {
s = fmt.Sprintf("[%d]", at.Len)
}
return s + at.Type.String(pm, pkgOverride)
}
func (at *ArrayType) addImports(im map[string]bool) { at.Type.addImports(im) }
// ChanType is a channel type.
type ChanType struct {
Dir ChanDir // 0, 1 or 2
Type Type
}
func (ct *ChanType) String(pm map[string]string, pkgOverride string) string {
s := ct.Type.String(pm, pkgOverride)
if ct.Dir == RecvDir {
return "<-chan " + s
}
if ct.Dir == SendDir {
return "chan<- " + s
}
return "chan " + s
}
func (ct *ChanType) addImports(im map[string]bool) { ct.Type.addImports(im) }
// ChanDir is a channel direction.
type ChanDir int
// Constants for channel directions.
const (
RecvDir ChanDir = 1
SendDir ChanDir = 2
)
// FuncType is a function type.
type FuncType struct {
In, Out []*Parameter
Variadic *Parameter // may be nil
}
func (ft *FuncType) String(pm map[string]string, pkgOverride string) string {
args := make([]string, len(ft.In))
for i, p := range ft.In {
args[i] = p.Type.String(pm, pkgOverride)
}
if ft.Variadic != nil {
args = append(args, "..."+ft.Variadic.Type.String(pm, pkgOverride))
}
rets := make([]string, len(ft.Out))
for i, p := range ft.Out {
rets[i] = p.Type.String(pm, pkgOverride)
}
retString := strings.Join(rets, ", ")
if nOut := len(ft.Out); nOut == 1 {
retString = " " + retString
} else if nOut > 1 {
retString = " (" + retString + ")"
}
return "func(" + strings.Join(args, ", ") + ")" + retString
}
func (ft *FuncType) addImports(im map[string]bool) {
for _, p := range ft.In {
p.Type.addImports(im)
}
if ft.Variadic != nil {
ft.Variadic.Type.addImports(im)
}
for _, p := range ft.Out {
p.Type.addImports(im)
}
}
// MapType is a map type.
type MapType struct {
Key, Value Type
}
func (mt *MapType) String(pm map[string]string, pkgOverride string) string {
return "map[" + mt.Key.String(pm, pkgOverride) + "]" + mt.Value.String(pm, pkgOverride)
}
func (mt *MapType) addImports(im map[string]bool) {
mt.Key.addImports(im)
mt.Value.addImports(im)
}
// NamedType is an exported type in a package.
type NamedType struct {
Package string // may be empty
Type string
TypeParams *TypeParametersType
}
func (nt *NamedType) String(pm map[string]string, pkgOverride string) string {
if pkgOverride == nt.Package {
return nt.Type + nt.TypeParams.String(pm, pkgOverride)
}
prefix := pm[nt.Package]
if prefix != "" {
return prefix + "." + nt.Type + nt.TypeParams.String(pm, pkgOverride)
}
return nt.Type + nt.TypeParams.String(pm, pkgOverride)
}
func (nt *NamedType) addImports(im map[string]bool) {
if nt.Package != "" {
im[nt.Package] = true
}
nt.TypeParams.addImports(im)
}
// PointerType is a pointer to another type.
type PointerType struct {
Type Type
}
func (pt *PointerType) String(pm map[string]string, pkgOverride string) string {
return "*" + pt.Type.String(pm, pkgOverride)
}
func (pt *PointerType) addImports(im map[string]bool) { pt.Type.addImports(im) }
// PredeclaredType is a predeclared type such as "int".
type PredeclaredType string
func (pt PredeclaredType) String(map[string]string, string) string { return string(pt) }
func (pt PredeclaredType) addImports(map[string]bool) {}
// TypeParametersType contains type paramters for a NamedType.
type TypeParametersType struct {
TypeParameters []Type
}
func (tp *TypeParametersType) String(pm map[string]string, pkgOverride string) string {
if tp == nil || len(tp.TypeParameters) == 0 {
return ""
}
var sb strings.Builder
sb.WriteString("[")
for i, v := range tp.TypeParameters {
if i != 0 {
sb.WriteString(", ")
}
sb.WriteString(v.String(pm, pkgOverride))
}
sb.WriteString("]")
return sb.String()
}
func (tp *TypeParametersType) addImports(im map[string]bool) {
if tp == nil {
return
}
for _, v := range tp.TypeParameters {
v.addImports(im)
}
}
// The following code is intended to be called by the program generated by ../reflect.go.
// InterfaceFromInterfaceType returns a pointer to an interface for the
// given reflection interface type.
func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) {
if it.Kind() != reflect.Interface {
return nil, fmt.Errorf("%v is not an interface", it)
}
intf := &Interface{}
for i := 0; i < it.NumMethod(); i++ {
mt := it.Method(i)
// TODO: need to skip unexported methods? or just raise an error?
m := &Method{
Name: mt.Name,
}
var err error
m.In, m.Variadic, m.Out, err = funcArgsFromType(mt.Type)
if err != nil {
return nil, err
}
intf.AddMethod(m)
}
return intf, nil
}
// t's Kind must be a reflect.Func.
func funcArgsFromType(t reflect.Type) (in []*Parameter, variadic *Parameter, out []*Parameter, err error) {
nin := t.NumIn()
if t.IsVariadic() {
nin--
}
var p *Parameter
for i := 0; i < nin; i++ {
p, err = parameterFromType(t.In(i))
if err != nil {
return
}
in = append(in, p)
}
if t.IsVariadic() {
p, err = parameterFromType(t.In(nin).Elem())
if err != nil {
return
}
variadic = p
}
for i := 0; i < t.NumOut(); i++ {
p, err = parameterFromType(t.Out(i))
if err != nil {
return
}
out = append(out, p)
}
return
}
func parameterFromType(t reflect.Type) (*Parameter, error) {
tt, err := typeFromType(t)
if err != nil {
return nil, err
}
return &Parameter{Type: tt}, nil
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()
var byteType = reflect.TypeOf(byte(0))
func typeFromType(t reflect.Type) (Type, error) {
// Hack workaround for https://golang.org/issue/3853.
// This explicit check should not be necessary.
if t == byteType {
return PredeclaredType("byte"), nil
}
if imp := t.PkgPath(); imp != "" {
return &NamedType{
Package: impPath(imp),
Type: t.Name(),
}, nil
}
// only unnamed or predeclared types after here
// Lots of types have element types. Let's do the parsing and error checking for all of them.
var elemType Type
switch t.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
var err error
elemType, err = typeFromType(t.Elem())
if err != nil {
return nil, err
}
}
switch t.Kind() {
case reflect.Array:
return &ArrayType{
Len: t.Len(),
Type: elemType,
}, nil
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
return PredeclaredType(t.Kind().String()), nil
case reflect.Chan:
var dir ChanDir
switch t.ChanDir() {
case reflect.RecvDir:
dir = RecvDir
case reflect.SendDir:
dir = SendDir
}
return &ChanType{
Dir: dir,
Type: elemType,
}, nil
case reflect.Func:
in, variadic, out, err := funcArgsFromType(t)
if err != nil {
return nil, err
}
return &FuncType{
In: in,
Out: out,
Variadic: variadic,
}, nil
case reflect.Interface:
// Two special interfaces.
if t.NumMethod() == 0 {
return PredeclaredType("any"), nil
}
if t == errorType {
return PredeclaredType("error"), nil
}
case reflect.Map:
kt, err := typeFromType(t.Key())
if err != nil {
return nil, err
}
return &MapType{
Key: kt,
Value: elemType,
}, nil
case reflect.Ptr:
return &PointerType{
Type: elemType,
}, nil
case reflect.Slice:
return &ArrayType{
Len: -1,
Type: elemType,
}, nil
case reflect.Struct:
if t.NumField() == 0 {
return PredeclaredType("struct{}"), nil
}
}
// TODO: Struct, UnsafePointer
return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind())
}
// impPath sanitizes the package path returned by `PkgPath` method of a reflect Type so that
// it is importable. PkgPath might return a path that includes "vendor". These paths do not
// compile, so we need to remove everything up to and including "/vendor/".
// See https://github.com/golang/go/issues/12019.
func impPath(imp string) string {
if strings.HasPrefix(imp, "vendor/") {
imp = "/" + imp
}
if i := strings.LastIndex(imp, "/vendor/"); i != -1 {
imp = imp[i+len("/vendor/"):]
}
return imp
}
// ErrorInterface represent built-in error interface.
var ErrorInterface = Interface{
Name: "error",
Methods: []*Method{
{
Name: "Error",
Out: []*Parameter{
{
Name: "",
Type: PredeclaredType("string"),
},
},
},
},
}

802
vendor/go.uber.org/mock/mockgen/parse.go generated vendored Normal file
View File

@@ -0,0 +1,802 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
// This file contains the model construction by parsing source files.
import (
"errors"
"fmt"
"go/ast"
"go/build"
"go/importer"
"go/parser"
"go/token"
"go/types"
"log"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"go.uber.org/mock/mockgen/model"
)
// sourceMode generates mocks via source file.
func sourceMode(source string) (*model.Package, error) {
srcDir, err := filepath.Abs(filepath.Dir(source))
if err != nil {
return nil, fmt.Errorf("failed getting source directory: %v", err)
}
packageImport, err := parsePackageImport(srcDir)
if err != nil {
return nil, err
}
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, source, nil, 0)
if err != nil {
return nil, fmt.Errorf("failed parsing source file %v: %v", source, err)
}
p := &fileParser{
fileSet: fs,
imports: make(map[string]importedPackage),
importedInterfaces: newInterfaceCache(),
auxInterfaces: newInterfaceCache(),
srcDir: srcDir,
}
// Handle -imports.
dotImports := make(map[string]bool)
if *imports != "" {
for _, kv := range strings.Split(*imports, ",") {
eq := strings.Index(kv, "=")
k, v := kv[:eq], kv[eq+1:]
if k == "." {
dotImports[v] = true
} else {
p.imports[k] = importedPkg{path: v}
}
}
}
if *excludeInterfaces != "" {
p.excludeNamesSet = parseExcludeInterfaces(*excludeInterfaces)
}
// Handle -aux_files.
if err := p.parseAuxFiles(*auxFiles); err != nil {
return nil, err
}
p.addAuxInterfacesFromFile(packageImport, file) // this file
pkg, err := p.parseFile(packageImport, file)
if err != nil {
return nil, err
}
for pkgPath := range dotImports {
pkg.DotImports = append(pkg.DotImports, pkgPath)
}
return pkg, nil
}
type importedPackage interface {
Path() string
Parser() *fileParser
}
type importedPkg struct {
path string
parser *fileParser
}
func (i importedPkg) Path() string { return i.path }
func (i importedPkg) Parser() *fileParser { return i.parser }
// duplicateImport is a bit of a misnomer. Currently the parser can't
// handle cases of multi-file packages importing different packages
// under the same name. Often these imports would not be problematic,
// so this type lets us defer raising an error unless the package name
// is actually used.
type duplicateImport struct {
name string
duplicates []string
}
func (d duplicateImport) Error() string {
return fmt.Sprintf("%q is ambiguous because of duplicate imports: %v", d.name, d.duplicates)
}
func (d duplicateImport) Path() string { log.Fatal(d.Error()); return "" }
func (d duplicateImport) Parser() *fileParser { log.Fatal(d.Error()); return nil }
type interfaceCache struct {
m map[string]map[string]*namedInterface
}
func newInterfaceCache() *interfaceCache {
return &interfaceCache{
m: make(map[string]map[string]*namedInterface),
}
}
func (i *interfaceCache) Set(pkg, name string, it *namedInterface) {
if _, ok := i.m[pkg]; !ok {
i.m[pkg] = make(map[string]*namedInterface)
}
i.m[pkg][name] = it
}
func (i *interfaceCache) Get(pkg, name string) *namedInterface {
if _, ok := i.m[pkg]; !ok {
return nil
}
return i.m[pkg][name]
}
func (i *interfaceCache) GetASTIface(pkg, name string) *ast.InterfaceType {
if _, ok := i.m[pkg]; !ok {
return nil
}
it, ok := i.m[pkg][name]
if !ok {
return nil
}
return it.it
}
type fileParser struct {
fileSet *token.FileSet
imports map[string]importedPackage // package name => imported package
importedInterfaces *interfaceCache
auxFiles []*ast.File
auxInterfaces *interfaceCache
srcDir string
excludeNamesSet map[string]struct{}
}
func (p *fileParser) errorf(pos token.Pos, format string, args ...any) error {
ps := p.fileSet.Position(pos)
format = "%s:%d:%d: " + format
args = append([]any{ps.Filename, ps.Line, ps.Column}, args...)
return fmt.Errorf(format, args...)
}
func (p *fileParser) parseAuxFiles(auxFiles string) error {
auxFiles = strings.TrimSpace(auxFiles)
if auxFiles == "" {
return nil
}
for _, kv := range strings.Split(auxFiles, ",") {
parts := strings.SplitN(kv, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("bad aux file spec: %v", kv)
}
pkg, fpath := parts[0], parts[1]
file, err := parser.ParseFile(p.fileSet, fpath, nil, 0)
if err != nil {
return err
}
p.auxFiles = append(p.auxFiles, file)
p.addAuxInterfacesFromFile(pkg, file)
}
return nil
}
func (p *fileParser) addAuxInterfacesFromFile(pkg string, file *ast.File) {
for ni := range iterInterfaces(file) {
p.auxInterfaces.Set(pkg, ni.name.Name, ni)
}
}
// parseFile loads all file imports and auxiliary files import into the
// fileParser, parses all file interfaces and returns package model.
func (p *fileParser) parseFile(importPath string, file *ast.File) (*model.Package, error) {
allImports, dotImports := importsOfFile(file)
// Don't stomp imports provided by -imports. Those should take precedence.
for pkg, pkgI := range allImports {
if _, ok := p.imports[pkg]; !ok {
p.imports[pkg] = pkgI
}
}
// Add imports from auxiliary files, which might be needed for embedded interfaces.
// Don't stomp any other imports.
for _, f := range p.auxFiles {
auxImports, _ := importsOfFile(f)
for pkg, pkgI := range auxImports {
if _, ok := p.imports[pkg]; !ok {
p.imports[pkg] = pkgI
}
}
}
var is []*model.Interface
for ni := range iterInterfaces(file) {
if _, ok := p.excludeNamesSet[ni.name.String()]; ok {
continue
}
i, err := p.parseInterface(ni.name.String(), importPath, ni)
if err != nil {
return nil, err
}
is = append(is, i)
}
return &model.Package{
Name: file.Name.String(),
PkgPath: importPath,
Interfaces: is,
DotImports: dotImports,
}, nil
}
// parsePackage loads package specified by path, parses it and returns
// a new fileParser with the parsed imports and interfaces.
func (p *fileParser) parsePackage(path string) (*fileParser, error) {
newP := &fileParser{
fileSet: token.NewFileSet(),
imports: make(map[string]importedPackage),
importedInterfaces: newInterfaceCache(),
auxInterfaces: newInterfaceCache(),
srcDir: p.srcDir,
}
var pkgs map[string]*ast.Package
if imp, err := build.Import(path, newP.srcDir, build.FindOnly); err != nil {
return nil, err
} else if pkgs, err = parser.ParseDir(newP.fileSet, imp.Dir, nil, 0); err != nil {
return nil, err
}
for _, pkg := range pkgs {
file := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates|ast.FilterUnassociatedComments|ast.FilterImportDuplicates)
for ni := range iterInterfaces(file) {
newP.importedInterfaces.Set(path, ni.name.Name, ni)
}
imports, _ := importsOfFile(file)
for pkgName, pkgI := range imports {
newP.imports[pkgName] = pkgI
}
}
return newP, nil
}
func (p *fileParser) constructInstParams(pkg string, params []*ast.Field, instParams []model.Type, embeddedInstParams []ast.Expr, tps map[string]model.Type) ([]model.Type, error) {
pm := make(map[string]int)
var i int
for _, v := range params {
for _, n := range v.Names {
pm[n.Name] = i
instParams = append(instParams, model.PredeclaredType(n.Name))
i++
}
}
var runtimeInstParams []model.Type
for _, instParam := range embeddedInstParams {
switch t := instParam.(type) {
case *ast.Ident:
if idx, ok := pm[t.Name]; ok {
runtimeInstParams = append(runtimeInstParams, instParams[idx])
continue
}
}
modelType, err := p.parseType(pkg, instParam, tps)
if err != nil {
return nil, err
}
runtimeInstParams = append(runtimeInstParams, modelType)
}
return runtimeInstParams, nil
}
func (p *fileParser) constructTps(it *namedInterface) (tps map[string]model.Type) {
tps = make(map[string]model.Type)
n := 0
for _, tp := range it.typeParams {
for _, tm := range tp.Names {
tps[tm.Name] = nil
if len(it.instTypes) != 0 {
tps[tm.Name] = it.instTypes[n]
n++
}
}
}
return tps
}
// parseInterface loads interface specified by pkg and name, parses it and returns
// a new model with the parsed.
func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*model.Interface, error) {
iface := &model.Interface{Name: name}
tps := p.constructTps(it)
tp, err := p.parseFieldList(pkg, it.typeParams, tps)
if err != nil {
return nil, fmt.Errorf("unable to parse interface type parameters: %v", name)
}
iface.TypeParams = tp
for _, field := range it.it.Methods.List {
var methods []*model.Method
if methods, err = p.parseMethod(field, it, iface, pkg, tps); err != nil {
return nil, err
}
for _, m := range methods {
iface.AddMethod(m)
}
}
return iface, nil
}
func (p *fileParser) parseMethod(field *ast.Field, it *namedInterface, iface *model.Interface, pkg string, tps map[string]model.Type) ([]*model.Method, error) {
// {} for git diff
{
switch v := field.Type.(type) {
case *ast.FuncType:
if nn := len(field.Names); nn != 1 {
return nil, fmt.Errorf("expected one name for interface %v, got %d", iface.Name, nn)
}
m := &model.Method{
Name: field.Names[0].String(),
}
var err error
m.In, m.Variadic, m.Out, err = p.parseFunc(pkg, v, tps)
if err != nil {
return nil, err
}
return []*model.Method{m}, nil
case *ast.Ident:
// Embedded interface in this package.
embeddedIfaceType := p.auxInterfaces.Get(pkg, v.String())
if embeddedIfaceType == nil {
embeddedIfaceType = p.importedInterfaces.Get(pkg, v.String())
}
var embeddedIface *model.Interface
if embeddedIfaceType != nil {
var err error
embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps)
if err != nil {
return nil, err
}
embeddedIface, err = p.parseInterface(v.String(), pkg, embeddedIfaceType)
if err != nil {
return nil, err
}
} else {
// This is built-in error interface.
if v.String() == model.ErrorInterface.Name {
embeddedIface = &model.ErrorInterface
} else {
ip, err := p.parsePackage(pkg)
if err != nil {
return nil, p.errorf(v.Pos(), "could not parse package %s: %v", pkg, err)
}
if embeddedIfaceType = ip.importedInterfaces.Get(pkg, v.String()); embeddedIfaceType == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", pkg, v.String())
}
embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps)
if err != nil {
return nil, err
}
embeddedIface, err = ip.parseInterface(v.String(), pkg, embeddedIfaceType)
if err != nil {
return nil, err
}
}
}
return embeddedIface.Methods, nil
case *ast.SelectorExpr:
// Embedded interface in another package.
filePkg, sel := v.X.(*ast.Ident).String(), v.Sel.String()
embeddedPkg, ok := p.imports[filePkg]
if !ok {
return nil, p.errorf(v.X.Pos(), "unknown package %s", filePkg)
}
var embeddedIface *model.Interface
var err error
embeddedIfaceType := p.auxInterfaces.Get(filePkg, sel)
if embeddedIfaceType != nil {
embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps)
if err != nil {
return nil, err
}
embeddedIface, err = p.parseInterface(sel, filePkg, embeddedIfaceType)
if err != nil {
return nil, err
}
} else {
path := embeddedPkg.Path()
parser := embeddedPkg.Parser()
if parser == nil {
ip, err := p.parsePackage(path)
if err != nil {
return nil, p.errorf(v.Pos(), "could not parse package %s: %v", path, err)
}
parser = ip
p.imports[filePkg] = importedPkg{
path: embeddedPkg.Path(),
parser: parser,
}
}
if embeddedIfaceType = parser.importedInterfaces.Get(path, sel); embeddedIfaceType == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", path, sel)
}
embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps)
if err != nil {
return nil, err
}
embeddedIface, err = parser.parseInterface(sel, path, embeddedIfaceType)
if err != nil {
return nil, err
}
}
// TODO: apply shadowing rules.
return embeddedIface.Methods, nil
default:
return p.parseGenericMethod(field, it, iface, pkg, tps)
}
}
}
func (p *fileParser) parseFunc(pkg string, f *ast.FuncType, tps map[string]model.Type) (inParam []*model.Parameter, variadic *model.Parameter, outParam []*model.Parameter, err error) {
if f.Params != nil {
regParams := f.Params.List
if isVariadic(f) {
n := len(regParams)
varParams := regParams[n-1:]
regParams = regParams[:n-1]
vp, err := p.parseFieldList(pkg, varParams, tps)
if err != nil {
return nil, nil, nil, p.errorf(varParams[0].Pos(), "failed parsing variadic argument: %v", err)
}
variadic = vp[0]
}
inParam, err = p.parseFieldList(pkg, regParams, tps)
if err != nil {
return nil, nil, nil, p.errorf(f.Pos(), "failed parsing arguments: %v", err)
}
}
if f.Results != nil {
outParam, err = p.parseFieldList(pkg, f.Results.List, tps)
if err != nil {
return nil, nil, nil, p.errorf(f.Pos(), "failed parsing returns: %v", err)
}
}
return
}
func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field, tps map[string]model.Type) ([]*model.Parameter, error) {
nf := 0
for _, f := range fields {
nn := len(f.Names)
if nn == 0 {
nn = 1 // anonymous parameter
}
nf += nn
}
if nf == 0 {
return nil, nil
}
ps := make([]*model.Parameter, nf)
i := 0 // destination index
for _, f := range fields {
t, err := p.parseType(pkg, f.Type, tps)
if err != nil {
return nil, err
}
if len(f.Names) == 0 {
// anonymous arg
ps[i] = &model.Parameter{Type: t}
i++
continue
}
for _, name := range f.Names {
ps[i] = &model.Parameter{Name: name.Name, Type: t}
i++
}
}
return ps, nil
}
func (p *fileParser) parseType(pkg string, typ ast.Expr, tps map[string]model.Type) (model.Type, error) {
switch v := typ.(type) {
case *ast.ArrayType:
ln := -1
if v.Len != nil {
value, err := p.parseArrayLength(v.Len)
if err != nil {
return nil, err
}
ln, err = strconv.Atoi(value)
if err != nil {
return nil, p.errorf(v.Len.Pos(), "bad array size: %v", err)
}
}
t, err := p.parseType(pkg, v.Elt, tps)
if err != nil {
return nil, err
}
return &model.ArrayType{Len: ln, Type: t}, nil
case *ast.ChanType:
t, err := p.parseType(pkg, v.Value, tps)
if err != nil {
return nil, err
}
var dir model.ChanDir
if v.Dir == ast.SEND {
dir = model.SendDir
}
if v.Dir == ast.RECV {
dir = model.RecvDir
}
return &model.ChanType{Dir: dir, Type: t}, nil
case *ast.Ellipsis:
// assume we're parsing a variadic argument
return p.parseType(pkg, v.Elt, tps)
case *ast.FuncType:
in, variadic, out, err := p.parseFunc(pkg, v, tps)
if err != nil {
return nil, err
}
return &model.FuncType{In: in, Out: out, Variadic: variadic}, nil
case *ast.Ident:
it, ok := tps[v.Name]
if v.IsExported() && !ok {
// `pkg` may be an aliased imported pkg
// if so, patch the import w/ the fully qualified import
maybeImportedPkg, ok := p.imports[pkg]
if ok {
pkg = maybeImportedPkg.Path()
}
// assume type in this package
return &model.NamedType{Package: pkg, Type: v.Name}, nil
}
if ok && it != nil {
return it, nil
}
// assume predeclared type
return model.PredeclaredType(v.Name), nil
case *ast.InterfaceType:
if v.Methods != nil && len(v.Methods.List) > 0 {
return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed interface types")
}
return model.PredeclaredType("any"), nil
case *ast.MapType:
key, err := p.parseType(pkg, v.Key, tps)
if err != nil {
return nil, err
}
value, err := p.parseType(pkg, v.Value, tps)
if err != nil {
return nil, err
}
return &model.MapType{Key: key, Value: value}, nil
case *ast.SelectorExpr:
pkgName := v.X.(*ast.Ident).String()
pkg, ok := p.imports[pkgName]
if !ok {
return nil, p.errorf(v.Pos(), "unknown package %q", pkgName)
}
return &model.NamedType{Package: pkg.Path(), Type: v.Sel.String()}, nil
case *ast.StarExpr:
t, err := p.parseType(pkg, v.X, tps)
if err != nil {
return nil, err
}
return &model.PointerType{Type: t}, nil
case *ast.StructType:
if v.Fields != nil && len(v.Fields.List) > 0 {
return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed struct types")
}
return model.PredeclaredType("struct{}"), nil
case *ast.ParenExpr:
return p.parseType(pkg, v.X, tps)
default:
mt, err := p.parseGenericType(pkg, typ, tps)
if err != nil {
return nil, err
}
if mt == nil {
break
}
return mt, nil
}
return nil, fmt.Errorf("don't know how to parse type %T", typ)
}
func (p *fileParser) parseArrayLength(expr ast.Expr) (string, error) {
switch val := expr.(type) {
case (*ast.BasicLit):
return val.Value, nil
case (*ast.Ident):
// when the length is a const defined locally
return val.Obj.Decl.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value, nil
case (*ast.SelectorExpr):
// when the length is a const defined in an external package
usedPkg, err := importer.Default().Import(fmt.Sprintf("%s", val.X))
if err != nil {
return "", p.errorf(expr.Pos(), "unknown package in array length: %v", err)
}
ev, err := types.Eval(token.NewFileSet(), usedPkg, token.NoPos, val.Sel.Name)
if err != nil {
return "", p.errorf(expr.Pos(), "unknown constant in array length: %v", err)
}
return ev.Value.String(), nil
case (*ast.ParenExpr):
return p.parseArrayLength(val.X)
case (*ast.BinaryExpr):
x, err := p.parseArrayLength(val.X)
if err != nil {
return "", err
}
y, err := p.parseArrayLength(val.Y)
if err != nil {
return "", err
}
biExpr := fmt.Sprintf("%s%v%s", x, val.Op, y)
tv, err := types.Eval(token.NewFileSet(), nil, token.NoPos, biExpr)
if err != nil {
return "", p.errorf(expr.Pos(), "invalid expression in array length: %v", err)
}
return tv.Value.String(), nil
default:
return "", p.errorf(expr.Pos(), "invalid expression in array length: %v", val)
}
}
// importsOfFile returns a map of package name to import path
// of the imports in file.
func importsOfFile(file *ast.File) (normalImports map[string]importedPackage, dotImports []string) {
var importPaths []string
for _, is := range file.Imports {
if is.Name != nil {
continue
}
importPath := is.Path.Value[1 : len(is.Path.Value)-1] // remove quotes
importPaths = append(importPaths, importPath)
}
packagesName := createPackageMap(importPaths)
normalImports = make(map[string]importedPackage)
dotImports = make([]string, 0)
for _, is := range file.Imports {
var pkgName string
importPath := is.Path.Value[1 : len(is.Path.Value)-1] // remove quotes
if is.Name != nil {
// Named imports are always certain.
if is.Name.Name == "_" {
continue
}
pkgName = is.Name.Name
} else {
pkg, ok := packagesName[importPath]
if !ok {
// Fallback to import path suffix. Note that this is uncertain.
_, last := path.Split(importPath)
// If the last path component has dots, the first dot-delimited
// field is used as the name.
pkgName = strings.SplitN(last, ".", 2)[0]
} else {
pkgName = pkg
}
}
if pkgName == "." {
dotImports = append(dotImports, importPath)
} else {
if pkg, ok := normalImports[pkgName]; ok {
switch p := pkg.(type) {
case duplicateImport:
normalImports[pkgName] = duplicateImport{
name: p.name,
duplicates: append([]string{importPath}, p.duplicates...),
}
case importedPkg:
normalImports[pkgName] = duplicateImport{
name: pkgName,
duplicates: []string{p.path, importPath},
}
}
} else {
normalImports[pkgName] = importedPkg{path: importPath}
}
}
}
return
}
type namedInterface struct {
name *ast.Ident
it *ast.InterfaceType
typeParams []*ast.Field
embeddedInstTypeParams []ast.Expr
instTypes []model.Type
}
// Create an iterator over all interfaces in file.
func iterInterfaces(file *ast.File) <-chan *namedInterface {
ch := make(chan *namedInterface)
go func() {
for _, decl := range file.Decls {
gd, ok := decl.(*ast.GenDecl)
if !ok || gd.Tok != token.TYPE {
continue
}
for _, spec := range gd.Specs {
ts, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
it, ok := ts.Type.(*ast.InterfaceType)
if !ok {
continue
}
ch <- &namedInterface{name: ts.Name, it: it, typeParams: getTypeSpecTypeParams(ts)}
}
}
close(ch)
}()
return ch
}
// isVariadic returns whether the function is variadic.
func isVariadic(f *ast.FuncType) bool {
nargs := len(f.Params.List)
if nargs == 0 {
return false
}
_, ok := f.Params.List[nargs-1].Type.(*ast.Ellipsis)
return ok
}
// packageNameOfDir get package import path via dir
func packageNameOfDir(srcDir string) (string, error) {
files, err := os.ReadDir(srcDir)
if err != nil {
log.Fatal(err)
}
var goFilePath string
for _, file := range files {
if !file.IsDir() && strings.HasSuffix(file.Name(), ".go") {
goFilePath = file.Name()
break
}
}
if goFilePath == "" {
return "", fmt.Errorf("go source file not found %s", srcDir)
}
packageImport, err := parsePackageImport(srcDir)
if err != nil {
return "", err
}
return packageImport, nil
}
var errOutsideGoPath = errors.New("source directory is outside GOPATH")

255
vendor/go.uber.org/mock/mockgen/reflect.go generated vendored Normal file
View File

@@ -0,0 +1,255 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
// This file contains the model construction by reflection.
import (
"bytes"
"encoding/gob"
"flag"
"fmt"
"go/build"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"text/template"
"go.uber.org/mock/mockgen/model"
)
var (
progOnly = flag.Bool("prog_only", false, "(reflect mode) Only generate the reflection program; write it to stdout and exit.")
execOnly = flag.String("exec_only", "", "(reflect mode) If set, execute this reflection program.")
buildFlags = flag.String("build_flags", "", "(reflect mode) Additional flags for go build.")
)
// reflectMode generates mocks via reflection on an interface.
func reflectMode(importPath string, symbols []string) (*model.Package, error) {
if *execOnly != "" {
return run(*execOnly)
}
program, err := writeProgram(importPath, symbols)
if err != nil {
return nil, err
}
if *progOnly {
if _, err := os.Stdout.Write(program); err != nil {
return nil, err
}
os.Exit(0)
}
wd, _ := os.Getwd()
// Try to run the reflection program in the current working directory.
if p, err := runInDir(program, wd); err == nil {
return p, nil
}
// Try to run the program in the same directory as the input package.
if p, err := build.Import(importPath, wd, build.FindOnly); err == nil {
dir := p.Dir
if p, err := runInDir(program, dir); err == nil {
return p, nil
}
}
// Try to run it in a standard temp directory.
return runInDir(program, "")
}
func writeProgram(importPath string, symbols []string) ([]byte, error) {
var program bytes.Buffer
data := reflectData{
ImportPath: importPath,
Symbols: symbols,
}
if err := reflectProgram.Execute(&program, &data); err != nil {
return nil, err
}
return program.Bytes(), nil
}
// run the given program and parse the output as a model.Package.
func run(program string) (*model.Package, error) {
f, err := os.CreateTemp("", "")
if err != nil {
return nil, err
}
filename := f.Name()
defer os.Remove(filename)
if err := f.Close(); err != nil {
return nil, err
}
// Run the program.
cmd := exec.Command(program, "-output", filename)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, err
}
f, err = os.Open(filename)
if err != nil {
return nil, err
}
// Process output.
var pkg model.Package
if err := gob.NewDecoder(f).Decode(&pkg); err != nil {
return nil, err
}
if err := f.Close(); err != nil {
return nil, err
}
return &pkg, nil
}
// runInDir writes the given program into the given dir, runs it there, and
// parses the output as a model.Package.
func runInDir(program []byte, dir string) (*model.Package, error) {
// We use TempDir instead of TempFile so we can control the filename.
tmpDir, err := os.MkdirTemp(dir, "gomock_reflect_")
if err != nil {
return nil, err
}
defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Printf("failed to remove temp directory: %s", err)
}
}()
const progSource = "prog.go"
var progBinary = "prog.bin"
if runtime.GOOS == "windows" {
// Windows won't execute a program unless it has a ".exe" suffix.
progBinary += ".exe"
}
if err := os.WriteFile(filepath.Join(tmpDir, progSource), program, 0600); err != nil {
return nil, err
}
cmdArgs := []string{}
cmdArgs = append(cmdArgs, "build")
if *buildFlags != "" {
cmdArgs = append(cmdArgs, strings.Split(*buildFlags, " ")...)
}
cmdArgs = append(cmdArgs, "-o", progBinary, progSource)
// Build the program.
buf := bytes.NewBuffer(nil)
cmd := exec.Command("go", cmdArgs...)
cmd.Dir = tmpDir
cmd.Stdout = os.Stdout
cmd.Stderr = io.MultiWriter(os.Stderr, buf)
if err := cmd.Run(); err != nil {
sErr := buf.String()
if strings.Contains(sErr, `cannot find package "."`) &&
strings.Contains(sErr, "go.uber.org/mock/mockgen/model") {
fmt.Fprint(os.Stderr, "Please reference the steps in the README to fix this error:\n\thttps://go.uber.org/mock#reflect-vendoring-error.\n")
return nil, err
}
return nil, err
}
return run(filepath.Join(tmpDir, progBinary))
}
type reflectData struct {
ImportPath string
Symbols []string
}
// This program reflects on an interface value, and prints the
// gob encoding of a model.Package to standard output.
// JSON doesn't work because of the model.Type interface.
var reflectProgram = template.Must(template.New("program").Parse(`
package main
import (
"encoding/gob"
"flag"
"fmt"
"os"
"path"
"reflect"
"go.uber.org/mock/mockgen/model"
pkg_ {{printf "%q" .ImportPath}}
)
var output = flag.String("output", "", "The output file name, or empty to use stdout.")
func main() {
flag.Parse()
its := []struct{
sym string
typ reflect.Type
}{
{{range .Symbols}}
{ {{printf "%q" .}}, reflect.TypeOf((*pkg_.{{.}})(nil)).Elem()},
{{end}}
}
pkg := &model.Package{
// NOTE: This behaves contrary to documented behaviour if the
// package name is not the final component of the import path.
// The reflect package doesn't expose the package name, though.
Name: path.Base({{printf "%q" .ImportPath}}),
}
for _, it := range its {
intf, err := model.InterfaceFromInterfaceType(it.typ)
if err != nil {
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
os.Exit(1)
}
intf.Name = it.sym
pkg.Interfaces = append(pkg.Interfaces, intf)
}
outfile := os.Stdout
if len(*output) != 0 {
var err error
outfile, err = os.Create(*output)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to open output file %q", *output)
}
defer func() {
if err := outfile.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close output file %q", *output)
os.Exit(1)
}
}()
}
if err := gob.NewEncoder(outfile).Encode(pkg); err != nil {
fmt.Fprintf(os.Stderr, "gob encode: %v\n", err)
os.Exit(1)
}
}
`))

31
vendor/go.uber.org/mock/mockgen/version.go generated vendored Normal file
View File

@@ -0,0 +1,31 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"log"
"runtime/debug"
)
func printModuleVersion() {
if bi, exists := debug.ReadBuildInfo(); exists {
fmt.Println(bi.Main.Version)
} else {
log.Printf("No version information found. Make sure to use " +
"GO111MODULE=on when running 'go get' in order to use specific " +
"version of the binary.")
}
}

15
vendor/go.uber.org/multierr/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,15 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 100 # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

4
vendor/go.uber.org/multierr/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,4 @@
/vendor
cover.html
cover.out
/bin

95
vendor/go.uber.org/multierr/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,95 @@
Releases
========
v1.11.0 (2023-03-28)
====================
- `Errors` now supports any error that implements multiple-error
interface.
- Add `Every` function to allow checking if all errors in the chain
satisfies `errors.Is` against the target error.
v1.10.0 (2023-03-08)
====================
- Comply with Go 1.20's multiple-error interface.
- Drop Go 1.18 support.
Per the support policy, only Go 1.19 and 1.20 are supported now.
- Drop all non-test external dependencies.
v1.9.0 (2022-12-12)
===================
- Add `AppendFunc` that allow passsing functions to similar to
`AppendInvoke`.
- Bump up yaml.v3 dependency to 3.0.1.
v1.8.0 (2022-02-28)
===================
- `Combine`: perform zero allocations when there are no errors.
v1.7.0 (2021-05-06)
===================
- Add `AppendInvoke` to append into errors from `defer` blocks.
v1.6.0 (2020-09-14)
===================
- Actually drop library dependency on development-time tooling.
v1.5.0 (2020-02-24)
===================
- Drop library dependency on development-time tooling.
v1.4.0 (2019-11-04)
===================
- Add `AppendInto` function to more ergonomically build errors inside a
loop.
v1.3.0 (2019-10-29)
===================
- Switch to Go modules.
v1.2.0 (2019-09-26)
===================
- Support extracting and matching against wrapped errors with `errors.As`
and `errors.Is`.
v1.1.0 (2017-06-30)
===================
- Added an `Errors(error) []error` function to extract the underlying list of
errors for a multierr error.
v1.0.0 (2017-05-31)
===================
No changes since v0.2.0. This release is committing to making no breaking
changes to the current API in the 1.X series.
v0.2.0 (2017-04-11)
===================
- Repeatedly appending to the same error is now faster due to fewer
allocations.
v0.1.0 (2017-31-03)
===================
- Initial release

19
vendor/go.uber.org/multierr/LICENSE.txt generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2017-2021 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

38
vendor/go.uber.org/multierr/Makefile generated vendored Normal file
View File

@@ -0,0 +1,38 @@
# Directory to put `go install`ed binaries in.
export GOBIN ?= $(shell pwd)/bin
GO_FILES := $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
.PHONY: build
build:
go build ./...
.PHONY: test
test:
go test -race ./...
.PHONY: gofmt
gofmt:
$(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX))
@gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true
@[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false)
.PHONY: golint
golint:
@cd tools && go install golang.org/x/lint/golint
@$(GOBIN)/golint ./...
.PHONY: staticcheck
staticcheck:
@cd tools && go install honnef.co/go/tools/cmd/staticcheck
@$(GOBIN)/staticcheck ./...
.PHONY: lint
lint: gofmt golint staticcheck
.PHONY: cover
cover:
go test -race -coverprofile=cover.out -coverpkg=./... -v ./...
go tool cover -html=cover.out -o cover.html

43
vendor/go.uber.org/multierr/README.md generated vendored Normal file
View File

@@ -0,0 +1,43 @@
# multierr [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
`multierr` allows combining one or more Go `error`s together.
## Features
- **Idiomatic**:
multierr follows best practices in Go, and keeps your code idiomatic.
- It keeps the underlying error type hidden,
allowing you to deal in `error` values exclusively.
- It provides APIs to safely append into an error from a `defer` statement.
- **Performant**:
multierr is optimized for performance:
- It avoids allocations where possible.
- It utilizes slice resizing semantics to optimize common cases
like appending into the same error object from a loop.
- **Interoperable**:
multierr interoperates with the Go standard library's error APIs seamlessly:
- The `errors.Is` and `errors.As` functions *just work*.
- **Lightweight**:
multierr comes with virtually no dependencies.
## Installation
```bash
go get -u go.uber.org/multierr@latest
```
## Status
Stable: No breaking changes will be made before 2.0.
-------------------------------------------------------------------------------
Released under the [MIT License].
[MIT License]: LICENSE.txt
[doc-img]: https://pkg.go.dev/badge/go.uber.org/multierr
[doc]: https://pkg.go.dev/go.uber.org/multierr
[ci-img]: https://github.com/uber-go/multierr/actions/workflows/go.yml/badge.svg
[cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg
[ci]: https://github.com/uber-go/multierr/actions/workflows/go.yml
[cov]: https://codecov.io/gh/uber-go/multierr

646
vendor/go.uber.org/multierr/error.go generated vendored Normal file
View File

@@ -0,0 +1,646 @@
// Copyright (c) 2017-2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package multierr allows combining one or more errors together.
//
// # Overview
//
// Errors can be combined with the use of the Combine function.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// conn.Close(),
// )
//
// If only two errors are being combined, the Append function may be used
// instead.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// The underlying list of errors for a returned error object may be retrieved
// with the Errors function.
//
// errors := multierr.Errors(err)
// if len(errors) > 0 {
// fmt.Println("The following errors occurred:", errors)
// }
//
// # Appending from a loop
//
// You sometimes need to append into an error from a loop.
//
// var err error
// for _, item := range items {
// err = multierr.Append(err, process(item))
// }
//
// Cases like this may require knowledge of whether an individual instance
// failed. This usually requires introduction of a new variable.
//
// var err error
// for _, item := range items {
// if perr := process(item); perr != nil {
// log.Warn("skipping item", item)
// err = multierr.Append(err, perr)
// }
// }
//
// multierr includes AppendInto to simplify cases like this.
//
// var err error
// for _, item := range items {
// if multierr.AppendInto(&err, process(item)) {
// log.Warn("skipping item", item)
// }
// }
//
// This will append the error into the err variable, and return true if that
// individual error was non-nil.
//
// See [AppendInto] for more information.
//
// # Deferred Functions
//
// Go makes it possible to modify the return value of a function in a defer
// block if the function was using named returns. This makes it possible to
// record resource cleanup failures from deferred blocks.
//
// func sendRequest(req Request) (err error) {
// conn, err := openConnection()
// if err != nil {
// return err
// }
// defer func() {
// err = multierr.Append(err, conn.Close())
// }()
// // ...
// }
//
// multierr provides the Invoker type and AppendInvoke function to make cases
// like the above simpler and obviate the need for a closure. The following is
// roughly equivalent to the example above.
//
// func sendRequest(req Request) (err error) {
// conn, err := openConnection()
// if err != nil {
// return err
// }
// defer multierr.AppendInvoke(&err, multierr.Close(conn))
// // ...
// }
//
// See [AppendInvoke] and [Invoker] for more information.
//
// NOTE: If you're modifying an error from inside a defer, you MUST use a named
// return value for that function.
//
// # Advanced Usage
//
// Errors returned by Combine and Append MAY implement the following
// interface.
//
// type errorGroup interface {
// // Returns a slice containing the underlying list of errors.
// //
// // This slice MUST NOT be modified by the caller.
// Errors() []error
// }
//
// Note that if you need access to list of errors behind a multierr error, you
// should prefer using the Errors function. That said, if you need cheap
// read-only access to the underlying errors slice, you can attempt to cast
// the error to this interface. You MUST handle the failure case gracefully
// because errors returned by Combine and Append are not guaranteed to
// implement this interface.
//
// var errors []error
// group, ok := err.(errorGroup)
// if ok {
// errors = group.Errors()
// } else {
// errors = []error{err}
// }
package multierr // import "go.uber.org/multierr"
import (
"bytes"
"errors"
"fmt"
"io"
"strings"
"sync"
"sync/atomic"
)
var (
// Separator for single-line error messages.
_singlelineSeparator = []byte("; ")
// Prefix for multi-line messages
_multilinePrefix = []byte("the following errors occurred:")
// Prefix for the first and following lines of an item in a list of
// multi-line error messages.
//
// For example, if a single item is:
//
// foo
// bar
//
// It will become,
//
// - foo
// bar
_multilineSeparator = []byte("\n - ")
_multilineIndent = []byte(" ")
)
// _bufferPool is a pool of bytes.Buffers.
var _bufferPool = sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
type errorGroup interface {
Errors() []error
}
// Errors returns a slice containing zero or more errors that the supplied
// error is composed of. If the error is nil, a nil slice is returned.
//
// err := multierr.Append(r.Close(), w.Close())
// errors := multierr.Errors(err)
//
// If the error is not composed of other errors, the returned slice contains
// just the error that was passed in.
//
// Callers of this function are free to modify the returned slice.
func Errors(err error) []error {
return extractErrors(err)
}
// multiError is an error that holds one or more errors.
//
// An instance of this is guaranteed to be non-empty and flattened. That is,
// none of the errors inside multiError are other multiErrors.
//
// multiError formats to a semi-colon delimited list of error messages with
// %v and with a more readable multi-line format with %+v.
type multiError struct {
copyNeeded atomic.Bool
errors []error
}
// Errors returns the list of underlying errors.
//
// This slice MUST NOT be modified.
func (merr *multiError) Errors() []error {
if merr == nil {
return nil
}
return merr.errors
}
func (merr *multiError) Error() string {
if merr == nil {
return ""
}
buff := _bufferPool.Get().(*bytes.Buffer)
buff.Reset()
merr.writeSingleline(buff)
result := buff.String()
_bufferPool.Put(buff)
return result
}
// Every compares every error in the given err against the given target error
// using [errors.Is], and returns true only if every comparison returned true.
func Every(err error, target error) bool {
for _, e := range extractErrors(err) {
if !errors.Is(e, target) {
return false
}
}
return true
}
func (merr *multiError) Format(f fmt.State, c rune) {
if c == 'v' && f.Flag('+') {
merr.writeMultiline(f)
} else {
merr.writeSingleline(f)
}
}
func (merr *multiError) writeSingleline(w io.Writer) {
first := true
for _, item := range merr.errors {
if first {
first = false
} else {
w.Write(_singlelineSeparator)
}
io.WriteString(w, item.Error())
}
}
func (merr *multiError) writeMultiline(w io.Writer) {
w.Write(_multilinePrefix)
for _, item := range merr.errors {
w.Write(_multilineSeparator)
writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
}
}
// Writes s to the writer with the given prefix added before each line after
// the first.
func writePrefixLine(w io.Writer, prefix []byte, s string) {
first := true
for len(s) > 0 {
if first {
first = false
} else {
w.Write(prefix)
}
idx := strings.IndexByte(s, '\n')
if idx < 0 {
idx = len(s) - 1
}
io.WriteString(w, s[:idx+1])
s = s[idx+1:]
}
}
type inspectResult struct {
// Number of top-level non-nil errors
Count int
// Total number of errors including multiErrors
Capacity int
// Index of the first non-nil error in the list. Value is meaningless if
// Count is zero.
FirstErrorIdx int
// Whether the list contains at least one multiError
ContainsMultiError bool
}
// Inspects the given slice of errors so that we can efficiently allocate
// space for it.
func inspect(errors []error) (res inspectResult) {
first := true
for i, err := range errors {
if err == nil {
continue
}
res.Count++
if first {
first = false
res.FirstErrorIdx = i
}
if merr, ok := err.(*multiError); ok {
res.Capacity += len(merr.errors)
res.ContainsMultiError = true
} else {
res.Capacity++
}
}
return
}
// fromSlice converts the given list of errors into a single error.
func fromSlice(errors []error) error {
// Don't pay to inspect small slices.
switch len(errors) {
case 0:
return nil
case 1:
return errors[0]
}
res := inspect(errors)
switch res.Count {
case 0:
return nil
case 1:
// only one non-nil entry
return errors[res.FirstErrorIdx]
case len(errors):
if !res.ContainsMultiError {
// Error list is flat. Make a copy of it
// Otherwise "errors" escapes to the heap
// unconditionally for all other cases.
// This lets us optimize for the "no errors" case.
out := append(([]error)(nil), errors...)
return &multiError{errors: out}
}
}
nonNilErrs := make([]error, 0, res.Capacity)
for _, err := range errors[res.FirstErrorIdx:] {
if err == nil {
continue
}
if nested, ok := err.(*multiError); ok {
nonNilErrs = append(nonNilErrs, nested.errors...)
} else {
nonNilErrs = append(nonNilErrs, err)
}
}
return &multiError{errors: nonNilErrs}
}
// Combine combines the passed errors into a single error.
//
// If zero arguments were passed or if all items are nil, a nil error is
// returned.
//
// Combine(nil, nil) // == nil
//
// If only a single error was passed, it is returned as-is.
//
// Combine(err) // == err
//
// Combine skips over nil arguments so this function may be used to combine
// together errors from operations that fail independently of each other.
//
// multierr.Combine(
// reader.Close(),
// writer.Close(),
// pipe.Close(),
// )
//
// If any of the passed errors is a multierr error, it will be flattened along
// with the other errors.
//
// multierr.Combine(multierr.Combine(err1, err2), err3)
// // is the same as
// multierr.Combine(err1, err2, err3)
//
// The returned error formats into a readable multi-line error message if
// formatted with %+v.
//
// fmt.Sprintf("%+v", multierr.Combine(err1, err2))
func Combine(errors ...error) error {
return fromSlice(errors)
}
// Append appends the given errors together. Either value may be nil.
//
// This function is a specialization of Combine for the common case where
// there are only two errors.
//
// err = multierr.Append(reader.Close(), writer.Close())
//
// The following pattern may also be used to record failure of deferred
// operations without losing information about the original error.
//
// func doSomething(..) (err error) {
// f := acquireResource()
// defer func() {
// err = multierr.Append(err, f.Close())
// }()
//
// Note that the variable MUST be a named return to append an error to it from
// the defer statement. See also [AppendInvoke].
func Append(left error, right error) error {
switch {
case left == nil:
return right
case right == nil:
return left
}
if _, ok := right.(*multiError); !ok {
if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
// Common case where the error on the left is constantly being
// appended to.
errs := append(l.errors, right)
return &multiError{errors: errs}
} else if !ok {
// Both errors are single errors.
return &multiError{errors: []error{left, right}}
}
}
// Either right or both, left and right, are multiErrors. Rely on usual
// expensive logic.
errors := [2]error{left, right}
return fromSlice(errors[0:])
}
// AppendInto appends an error into the destination of an error pointer and
// returns whether the error being appended was non-nil.
//
// var err error
// multierr.AppendInto(&err, r.Close())
// multierr.AppendInto(&err, w.Close())
//
// The above is equivalent to,
//
// err := multierr.Append(r.Close(), w.Close())
//
// As AppendInto reports whether the provided error was non-nil, it may be
// used to build a multierr error in a loop more ergonomically. For example:
//
// var err error
// for line := range lines {
// var item Item
// if multierr.AppendInto(&err, parse(line, &item)) {
// continue
// }
// items = append(items, item)
// }
//
// Compare this with a version that relies solely on Append:
//
// var err error
// for line := range lines {
// var item Item
// if parseErr := parse(line, &item); parseErr != nil {
// err = multierr.Append(err, parseErr)
// continue
// }
// items = append(items, item)
// }
func AppendInto(into *error, err error) (errored bool) {
if into == nil {
// We panic if 'into' is nil. This is not documented above
// because suggesting that the pointer must be non-nil may
// confuse users into thinking that the error that it points
// to must be non-nil.
panic("misuse of multierr.AppendInto: into pointer must not be nil")
}
if err == nil {
return false
}
*into = Append(*into, err)
return true
}
// Invoker is an operation that may fail with an error. Use it with
// AppendInvoke to append the result of calling the function into an error.
// This allows you to conveniently defer capture of failing operations.
//
// See also, [Close] and [Invoke].
type Invoker interface {
Invoke() error
}
// Invoke wraps a function which may fail with an error to match the Invoker
// interface. Use it to supply functions matching this signature to
// AppendInvoke.
//
// For example,
//
// func processReader(r io.Reader) (err error) {
// scanner := bufio.NewScanner(r)
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
// for scanner.Scan() {
// // ...
// }
// // ...
// }
//
// In this example, the following line will construct the Invoker right away,
// but defer the invocation of scanner.Err() until the function returns.
//
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
//
// Note that the error you're appending to from the defer statement MUST be a
// named return.
type Invoke func() error
// Invoke calls the supplied function and returns its result.
func (i Invoke) Invoke() error { return i() }
// Close builds an Invoker that closes the provided io.Closer. Use it with
// AppendInvoke to close io.Closers and append their results into an error.
//
// For example,
//
// func processFile(path string) (err error) {
// f, err := os.Open(path)
// if err != nil {
// return err
// }
// defer multierr.AppendInvoke(&err, multierr.Close(f))
// return processReader(f)
// }
//
// In this example, multierr.Close will construct the Invoker right away, but
// defer the invocation of f.Close until the function returns.
//
// defer multierr.AppendInvoke(&err, multierr.Close(f))
//
// Note that the error you're appending to from the defer statement MUST be a
// named return.
func Close(closer io.Closer) Invoker {
return Invoke(closer.Close)
}
// AppendInvoke appends the result of calling the given Invoker into the
// provided error pointer. Use it with named returns to safely defer
// invocation of fallible operations until a function returns, and capture the
// resulting errors.
//
// func doSomething(...) (err error) {
// // ...
// f, err := openFile(..)
// if err != nil {
// return err
// }
//
// // multierr will call f.Close() when this function returns and
// // if the operation fails, its append its error into the
// // returned error.
// defer multierr.AppendInvoke(&err, multierr.Close(f))
//
// scanner := bufio.NewScanner(f)
// // Similarly, this scheduled scanner.Err to be called and
// // inspected when the function returns and append its error
// // into the returned error.
// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
//
// // ...
// }
//
// NOTE: If used with a defer, the error variable MUST be a named return.
//
// Without defer, AppendInvoke behaves exactly like AppendInto.
//
// err := // ...
// multierr.AppendInvoke(&err, mutltierr.Invoke(foo))
//
// // ...is roughly equivalent to...
//
// err := // ...
// multierr.AppendInto(&err, foo())
//
// The advantage of the indirection introduced by Invoker is to make it easy
// to defer the invocation of a function. Without this indirection, the
// invoked function will be evaluated at the time of the defer block rather
// than when the function returns.
//
// // BAD: This is likely not what the caller intended. This will evaluate
// // foo() right away and append its result into the error when the
// // function returns.
// defer multierr.AppendInto(&err, foo())
//
// // GOOD: This will defer invocation of foo unutil the function returns.
// defer multierr.AppendInvoke(&err, multierr.Invoke(foo))
//
// multierr provides a few Invoker implementations out of the box for
// convenience. See [Invoker] for more information.
func AppendInvoke(into *error, invoker Invoker) {
AppendInto(into, invoker.Invoke())
}
// AppendFunc is a shorthand for [AppendInvoke].
// It allows using function or method value directly
// without having to wrap it into an [Invoker] interface.
//
// func doSomething(...) (err error) {
// w, err := startWorker(...)
// if err != nil {
// return err
// }
//
// // multierr will call w.Stop() when this function returns and
// // if the operation fails, it appends its error into the
// // returned error.
// defer multierr.AppendFunc(&err, w.Stop)
// }
func AppendFunc(into *error, fn func() error) {
AppendInvoke(into, Invoke(fn))
}

48
vendor/go.uber.org/multierr/error_post_go120.go generated vendored Normal file
View File

@@ -0,0 +1,48 @@
// Copyright (c) 2017-2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build go1.20
// +build go1.20
package multierr
// Unwrap returns a list of errors wrapped by this multierr.
func (merr *multiError) Unwrap() []error {
return merr.Errors()
}
type multipleErrors interface {
Unwrap() []error
}
func extractErrors(err error) []error {
if err == nil {
return nil
}
// check if the given err is an Unwrapable error that
// implements multipleErrors interface.
eg, ok := err.(multipleErrors)
if !ok {
return []error{err}
}
return append(([]error)(nil), eg.Unwrap()...)
}

79
vendor/go.uber.org/multierr/error_pre_go120.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
// Copyright (c) 2017-2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build !go1.20
// +build !go1.20
package multierr
import "errors"
// Versions of Go before 1.20 did not support the Unwrap() []error method.
// This provides a similar behavior by implementing the Is(..) and As(..)
// methods.
// See the errors.Join proposal for details:
// https://github.com/golang/go/issues/53435
// As attempts to find the first error in the error list that matches the type
// of the value that target points to.
//
// This function allows errors.As to traverse the values stored on the
// multierr error.
func (merr *multiError) As(target interface{}) bool {
for _, err := range merr.Errors() {
if errors.As(err, target) {
return true
}
}
return false
}
// Is attempts to match the provided error against errors in the error list.
//
// This function allows errors.Is to traverse the values stored on the
// multierr error.
func (merr *multiError) Is(target error) bool {
for _, err := range merr.Errors() {
if errors.Is(err, target) {
return true
}
}
return false
}
func extractErrors(err error) []error {
if err == nil {
return nil
}
// Note that we're casting to multiError, not errorGroup. Our contract is
// that returned errors MAY implement errorGroup. Errors, however, only
// has special behavior for multierr-specific error objects.
//
// This behavior can be expanded in the future but I think it's prudent to
// start with as little as possible in terms of contract and possibility
// of misuse.
eg, ok := err.(*multiError)
if !ok {
return []error{err}
}
return append(([]error)(nil), eg.Errors()...)
}

17
vendor/go.uber.org/zap/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,17 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 95% # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure
ignore:
- internal/readme/readme.go

32
vendor/go.uber.org/zap/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,32 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
vendor
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.pprof
*.out
*.log
/bin
cover.out
cover.html

77
vendor/go.uber.org/zap/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,77 @@
output:
# Make output more digestible with quickfix in vim/emacs/etc.
sort-results: true
print-issued-lines: false
linters:
# We'll track the golangci-lint default linters manually
# instead of letting them change without our control.
disable-all: true
enable:
# golangci-lint defaults:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
# Our own extras:
- gofmt
- nolintlint # lints nolint directives
- revive
linters-settings:
govet:
# These govet checks are disabled by default, but they're useful.
enable:
- niliness
- reflectvaluecompare
- sortslice
- unusedwrite
errcheck:
exclude-functions:
# These methods can not fail.
# They operate on an in-memory buffer.
- (*go.uber.org/zap/buffer.Buffer).Write
- (*go.uber.org/zap/buffer.Buffer).WriteByte
- (*go.uber.org/zap/buffer.Buffer).WriteString
- (*go.uber.org/zap/zapio.Writer).Close
- (*go.uber.org/zap/zapio.Writer).Sync
- (*go.uber.org/zap/zapio.Writer).Write
# Write to zapio.Writer cannot fail,
# so io.WriteString on it cannot fail.
- io.WriteString(*go.uber.org/zap/zapio.Writer)
# Writing a plain string to a fmt.State cannot fail.
- io.WriteString(fmt.State)
issues:
# Print all issues reported by all linters.
max-issues-per-linter: 0
max-same-issues: 0
# Don't ignore some of the issues that golangci-lint considers okay.
# This includes documenting all exported entities.
exclude-use-default: false
exclude-rules:
# Don't warn on unused parameters.
# Parameter names are useful; replacing them with '_' is undesirable.
- linters: [revive]
text: 'unused-parameter: parameter \S+ seems to be unused, consider removing or renaming it as _'
# staticcheck already has smarter checks for empty blocks.
# revive's empty-block linter has false positives.
# For example, as of writing this, the following is not allowed.
# for foo() { }
- linters: [revive]
text: 'empty-block: this block is empty, you can remove it'
# Ignore logger.Sync() errcheck failures in example_test.go
# since those are intended to be uncomplicated examples.
- linters: [errcheck]
path: example_test.go
text: 'Error return value of `logger.Sync` is not checked'

109
vendor/go.uber.org/zap/.readme.tmpl generated vendored Normal file
View File

@@ -0,0 +1,109 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
{{.BenchmarkAddingFields}}
Log a message with a logger that already has 10 fields of context:
{{.BenchmarkAccumulatedContext}}
Log a static string, without any context or `printf`-style templating:
{{.BenchmarkWithoutFields}}
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
oss-conduct@uber.com. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in the [benchmarks/go.mod][] file. [↩](#anchor-versions)
[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap
[doc]: https://pkg.go.dev/go.uber.org/zap
[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg
[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod

671
vendor/go.uber.org/zap/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,671 @@
# Changelog
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.26.0 (14 Sep 2023)
Enhancements:
* [#1319][]: Add `WithLazy` method to `Logger` which lazily evaluates the structured
context.
* [#1350][]: String encoding is much (~50%) faster now.
Thanks to @jquirke, @cdvr1993 for their contributions to this release.
[#1319]: https://github.com/uber-go/zap/pull/1319
[#1350]: https://github.com/uber-go/zap/pull/1350
## 1.25.0 (1 Aug 2023)
This release contains several improvements including performance, API additions,
and two new experimental packages whose APIs are unstable and may change in the
future.
Enhancements:
* [#1246][]: Add `zap/exp/zapslog` package for integration with slog.
* [#1273][]: Add `Name` to `Logger` which returns the Logger's name if one is set.
* [#1281][]: Add `zap/exp/expfield` package which contains helper methods
`Str` and `Strs` for constructing String-like zap.Fields.
* [#1310][]: Reduce stack size on `Any`.
Thanks to @knight42, @dzakaammar, @bcspragu, and @rexywork for their contributions
to this release.
[#1246]: https://github.com/uber-go/zap/pull/1246
[#1273]: https://github.com/uber-go/zap/pull/1273
[#1281]: https://github.com/uber-go/zap/pull/1281
[#1310]: https://github.com/uber-go/zap/pull/1310
## 1.24.0 (30 Nov 2022)
Enhancements:
* [#1148][]: Add `Level` to both `Logger` and `SugaredLogger` that reports the
current minimum enabled log level.
* [#1185][]: `SugaredLogger` turns errors to zap.Error automatically.
Thanks to @Abirdcfly, @craigpastro, @nnnkkk7, and @sashamelentyev for their
contributions to this release.
[#1148]: https://github.coml/uber-go/zap/pull/1148
[#1185]: https://github.coml/uber-go/zap/pull/1185
## 1.23.0 (24 Aug 2022)
Enhancements:
* [#1147][]: Add a `zapcore.LevelOf` function to determine the level of a
`LevelEnabler` or `Core`.
* [#1155][]: Add `zap.Stringers` field constructor to log arrays of objects
that implement `String() string`.
[#1147]: https://github.com/uber-go/zap/pull/1147
[#1155]: https://github.com/uber-go/zap/pull/1155
## 1.22.0 (8 Aug 2022)
Enhancements:
* [#1071][]: Add `zap.Objects` and `zap.ObjectValues` field constructors to log
arrays of objects. With these two constructors, you don't need to implement
`zapcore.ArrayMarshaler` for use with `zap.Array` if those objects implement
`zapcore.ObjectMarshaler`.
* [#1079][]: Add `SugaredLogger.WithOptions` to build a copy of an existing
`SugaredLogger` with the provided options applied.
* [#1080][]: Add `*ln` variants to `SugaredLogger` for each log level.
These functions provide a string joining behavior similar to `fmt.Println`.
* [#1088][]: Add `zap.WithFatalHook` option to control the behavior of the
logger for `Fatal`-level log entries. This defaults to exiting the program.
* [#1108][]: Add a `zap.Must` function that you can use with `NewProduction` or
`NewDevelopment` to panic if the system was unable to build the logger.
* [#1118][]: Add a `Logger.Log` method that allows specifying the log level for
a statement dynamically.
Thanks to @cardil, @craigpastro, @sashamelentyev, @shota3506, and @zhupeijun
for their contributions to this release.
[#1071]: https://github.com/uber-go/zap/pull/1071
[#1079]: https://github.com/uber-go/zap/pull/1079
[#1080]: https://github.com/uber-go/zap/pull/1080
[#1088]: https://github.com/uber-go/zap/pull/1088
[#1108]: https://github.com/uber-go/zap/pull/1108
[#1118]: https://github.com/uber-go/zap/pull/1118
## 1.21.0 (7 Feb 2022)
Enhancements:
* [#1047][]: Add `zapcore.ParseLevel` to parse a `Level` from a string.
* [#1048][]: Add `zap.ParseAtomicLevel` to parse an `AtomicLevel` from a
string.
Bugfixes:
* [#1058][]: Fix panic in JSON encoder when `EncodeLevel` is unset.
Other changes:
* [#1052][]: Improve encoding performance when the `AddCaller` and
`AddStacktrace` options are used together.
[#1047]: https://github.com/uber-go/zap/pull/1047
[#1048]: https://github.com/uber-go/zap/pull/1048
[#1052]: https://github.com/uber-go/zap/pull/1052
[#1058]: https://github.com/uber-go/zap/pull/1058
Thanks to @aerosol and @Techassi for their contributions to this release.
## 1.20.0 (4 Jan 2022)
Enhancements:
* [#989][]: Add `EncoderConfig.SkipLineEnding` flag to disable adding newline
characters between log statements.
* [#1039][]: Add `EncoderConfig.NewReflectedEncoder` field to customize JSON
encoding of reflected log fields.
Bugfixes:
* [#1011][]: Fix inaccurate precision when encoding complex64 as JSON.
* [#554][], [#1017][]: Close JSON namespaces opened in `MarshalLogObject`
methods when the methods return.
* [#1033][]: Avoid panicking in Sampler core if `thereafter` is zero.
Other changes:
* [#1028][]: Drop support for Go < 1.15.
[#554]: https://github.com/uber-go/zap/pull/554
[#989]: https://github.com/uber-go/zap/pull/989
[#1011]: https://github.com/uber-go/zap/pull/1011
[#1017]: https://github.com/uber-go/zap/pull/1017
[#1028]: https://github.com/uber-go/zap/pull/1028
[#1033]: https://github.com/uber-go/zap/pull/1033
[#1039]: https://github.com/uber-go/zap/pull/1039
Thanks to @psrajat, @lruggieri, @sammyrnycreal for their contributions to this release.
## 1.19.1 (8 Sep 2021)
Bugfixes:
* [#1001][]: JSON: Fix complex number encoding with negative imaginary part. Thanks to @hemantjadon.
* [#1003][]: JSON: Fix inaccurate precision when encoding float32.
[#1001]: https://github.com/uber-go/zap/pull/1001
[#1003]: https://github.com/uber-go/zap/pull/1003
## 1.19.0 (9 Aug 2021)
Enhancements:
* [#975][]: Avoid panicking in Sampler core if the level is out of bounds.
* [#984][]: Reduce the size of BufferedWriteSyncer by aligning the fields
better.
[#975]: https://github.com/uber-go/zap/pull/975
[#984]: https://github.com/uber-go/zap/pull/984
Thanks to @lancoLiu and @thockin for their contributions to this release.
## 1.18.1 (28 Jun 2021)
Bugfixes:
* [#974][]: Fix nil dereference in logger constructed by `zap.NewNop`.
[#974]: https://github.com/uber-go/zap/pull/974
## 1.18.0 (28 Jun 2021)
Enhancements:
* [#961][]: Add `zapcore.BufferedWriteSyncer`, a new `WriteSyncer` that buffers
messages in-memory and flushes them periodically.
* [#971][]: Add `zapio.Writer` to use a Zap logger as an `io.Writer`.
* [#897][]: Add `zap.WithClock` option to control the source of time via the
new `zapcore.Clock` interface.
* [#949][]: Avoid panicking in `zap.SugaredLogger` when arguments of `*w`
methods don't match expectations.
* [#943][]: Add support for filtering by level or arbitrary matcher function to
`zaptest/observer`.
* [#691][]: Comply with `io.StringWriter` and `io.ByteWriter` in Zap's
`buffer.Buffer`.
Thanks to @atrn0, @ernado, @heyanfu, @hnlq715, @zchee
for their contributions to this release.
[#691]: https://github.com/uber-go/zap/pull/691
[#897]: https://github.com/uber-go/zap/pull/897
[#943]: https://github.com/uber-go/zap/pull/943
[#949]: https://github.com/uber-go/zap/pull/949
[#961]: https://github.com/uber-go/zap/pull/961
[#971]: https://github.com/uber-go/zap/pull/971
## 1.17.0 (25 May 2021)
Bugfixes:
* [#867][]: Encode `<nil>` for nil `error` instead of a panic.
* [#931][], [#936][]: Update minimum version constraints to address
vulnerabilities in dependencies.
Enhancements:
* [#865][]: Improve alignment of fields of the Logger struct, reducing its
size from 96 to 80 bytes.
* [#881][]: Support `grpclog.LoggerV2` in zapgrpc.
* [#903][]: Support URL-encoded POST requests to the AtomicLevel HTTP handler
with the `application/x-www-form-urlencoded` content type.
* [#912][]: Support multi-field encoding with `zap.Inline`.
* [#913][]: Speed up SugaredLogger for calls with a single string.
* [#928][]: Add support for filtering by field name to `zaptest/observer`.
Thanks to @ash2k, @FMLS, @jimmystewpot, @Oncilla, @tsoslow, @tylitianrui, @withshubh, and @wziww for their contributions to this release.
[#865]: https://github.com/uber-go/zap/pull/865
[#867]: https://github.com/uber-go/zap/pull/867
[#881]: https://github.com/uber-go/zap/pull/881
[#903]: https://github.com/uber-go/zap/pull/903
[#912]: https://github.com/uber-go/zap/pull/912
[#913]: https://github.com/uber-go/zap/pull/913
[#928]: https://github.com/uber-go/zap/pull/928
[#931]: https://github.com/uber-go/zap/pull/931
[#936]: https://github.com/uber-go/zap/pull/936
## 1.16.0 (1 Sep 2020)
Bugfixes:
* [#828][]: Fix missing newline in IncreaseLevel error messages.
* [#835][]: Fix panic in JSON encoder when encoding times or durations
without specifying a time or duration encoder.
* [#843][]: Honor CallerSkip when taking stack traces.
* [#862][]: Fix the default file permissions to use `0666` and rely on the umask instead.
* [#854][]: Encode `<nil>` for nil `Stringer` instead of a panic error log.
Enhancements:
* [#629][]: Added `zapcore.TimeEncoderOfLayout` to easily create time encoders
for custom layouts.
* [#697][]: Added support for a configurable delimiter in the console encoder.
* [#852][]: Optimize console encoder by pooling the underlying JSON encoder.
* [#844][]: Add ability to include the calling function as part of logs.
* [#843][]: Add `StackSkip` for including truncated stacks as a field.
* [#861][]: Add options to customize Fatal behaviour for better testability.
Thanks to @SteelPhase, @tmshn, @lixingwang, @wyxloading, @moul, @segevfiner, @andy-retailnext and @jcorbin for their contributions to this release.
[#629]: https://github.com/uber-go/zap/pull/629
[#697]: https://github.com/uber-go/zap/pull/697
[#828]: https://github.com/uber-go/zap/pull/828
[#835]: https://github.com/uber-go/zap/pull/835
[#843]: https://github.com/uber-go/zap/pull/843
[#844]: https://github.com/uber-go/zap/pull/844
[#852]: https://github.com/uber-go/zap/pull/852
[#854]: https://github.com/uber-go/zap/pull/854
[#861]: https://github.com/uber-go/zap/pull/861
[#862]: https://github.com/uber-go/zap/pull/862
## 1.15.0 (23 Apr 2020)
Bugfixes:
* [#804][]: Fix handling of `Time` values out of `UnixNano` range.
* [#812][]: Fix `IncreaseLevel` being reset after a call to `With`.
Enhancements:
* [#806][]: Add `WithCaller` option to supersede the `AddCaller` option. This
allows disabling annotation of log entries with caller information if
previously enabled with `AddCaller`.
* [#813][]: Deprecate `NewSampler` constructor in favor of
`NewSamplerWithOptions` which supports a `SamplerHook` option. This option
adds support for monitoring sampling decisions through a hook.
Thanks to @danielbprice for their contributions to this release.
[#804]: https://github.com/uber-go/zap/pull/804
[#812]: https://github.com/uber-go/zap/pull/812
[#806]: https://github.com/uber-go/zap/pull/806
[#813]: https://github.com/uber-go/zap/pull/813
## 1.14.1 (14 Mar 2020)
Bugfixes:
* [#791][]: Fix panic on attempting to build a logger with an invalid Config.
* [#795][]: Vendoring Zap with `go mod vendor` no longer includes Zap's
development-time dependencies.
* [#799][]: Fix issue introduced in 1.14.0 that caused invalid JSON output to
be generated for arrays of `time.Time` objects when using string-based time
formats.
Thanks to @YashishDua for their contributions to this release.
[#791]: https://github.com/uber-go/zap/pull/791
[#795]: https://github.com/uber-go/zap/pull/795
[#799]: https://github.com/uber-go/zap/pull/799
## 1.14.0 (20 Feb 2020)
Enhancements:
* [#771][]: Optimize calls for disabled log levels.
* [#773][]: Add millisecond duration encoder.
* [#775][]: Add option to increase the level of a logger.
* [#786][]: Optimize time formatters using `Time.AppendFormat` where possible.
Thanks to @caibirdme for their contributions to this release.
[#771]: https://github.com/uber-go/zap/pull/771
[#773]: https://github.com/uber-go/zap/pull/773
[#775]: https://github.com/uber-go/zap/pull/775
[#786]: https://github.com/uber-go/zap/pull/786
## 1.13.0 (13 Nov 2019)
Enhancements:
* [#758][]: Add `Intp`, `Stringp`, and other similar `*p` field constructors
to log pointers to primitives with support for `nil` values.
Thanks to @jbizzle for their contributions to this release.
[#758]: https://github.com/uber-go/zap/pull/758
## 1.12.0 (29 Oct 2019)
Enhancements:
* [#751][]: Migrate to Go modules.
[#751]: https://github.com/uber-go/zap/pull/751
## 1.11.0 (21 Oct 2019)
Enhancements:
* [#725][]: Add `zapcore.OmitKey` to omit keys in an `EncoderConfig`.
* [#736][]: Add `RFC3339` and `RFC3339Nano` time encoders.
Thanks to @juicemia, @uhthomas for their contributions to this release.
[#725]: https://github.com/uber-go/zap/pull/725
[#736]: https://github.com/uber-go/zap/pull/736
## 1.10.0 (29 Apr 2019)
Bugfixes:
* [#657][]: Fix `MapObjectEncoder.AppendByteString` not adding value as a
string.
* [#706][]: Fix incorrect call depth to determine caller in Go 1.12.
Enhancements:
* [#610][]: Add `zaptest.WrapOptions` to wrap `zap.Option` for creating test
loggers.
* [#675][]: Don't panic when encoding a String field.
* [#704][]: Disable HTML escaping for JSON objects encoded using the
reflect-based encoder.
Thanks to @iaroslav-ciupin, @lelenanam, @joa, @NWilson for their contributions
to this release.
[#657]: https://github.com/uber-go/zap/pull/657
[#706]: https://github.com/uber-go/zap/pull/706
[#610]: https://github.com/uber-go/zap/pull/610
[#675]: https://github.com/uber-go/zap/pull/675
[#704]: https://github.com/uber-go/zap/pull/704
## v1.9.1 (06 Aug 2018)
Bugfixes:
* [#614][]: MapObjectEncoder should not ignore empty slices.
[#614]: https://github.com/uber-go/zap/pull/614
## v1.9.0 (19 Jul 2018)
Enhancements:
* [#602][]: Reduce number of allocations when logging with reflection.
* [#572][], [#606][]: Expose a registry for third-party logging sinks.
Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and
@dimroc for their contributions to this release.
[#602]: https://github.com/uber-go/zap/pull/602
[#572]: https://github.com/uber-go/zap/pull/572
[#606]: https://github.com/uber-go/zap/pull/606
## v1.8.0 (13 Apr 2018)
Enhancements:
* [#508][]: Make log level configurable when redirecting the standard
library's logger.
* [#518][]: Add a logger that writes to a `*testing.TB`.
* [#577][]: Add a top-level alias for `zapcore.Field` to clean up GoDoc.
Bugfixes:
* [#574][]: Add a missing import comment to `go.uber.org/zap/buffer`.
Thanks to @DiSiqueira and @djui for their contributions to this release.
[#508]: https://github.com/uber-go/zap/pull/508
[#518]: https://github.com/uber-go/zap/pull/518
[#577]: https://github.com/uber-go/zap/pull/577
[#574]: https://github.com/uber-go/zap/pull/574
## v1.7.1 (25 Sep 2017)
Bugfixes:
* [#504][]: Store strings when using AddByteString with the map encoder.
[#504]: https://github.com/uber-go/zap/pull/504
## v1.7.0 (21 Sep 2017)
Enhancements:
* [#487][]: Add `NewStdLogAt`, which extends `NewStdLog` by allowing the user
to specify the level of the logged messages.
[#487]: https://github.com/uber-go/zap/pull/487
## v1.6.0 (30 Aug 2017)
Enhancements:
* [#491][]: Omit zap stack frames from stacktraces.
* [#490][]: Add a `ContextMap` method to observer logs for simpler
field validation in tests.
[#490]: https://github.com/uber-go/zap/pull/490
[#491]: https://github.com/uber-go/zap/pull/491
## v1.5.0 (22 Jul 2017)
Enhancements:
* [#460][] and [#470][]: Support errors produced by `go.uber.org/multierr`.
* [#465][]: Support user-supplied encoders for logger names.
Bugfixes:
* [#477][]: Fix a bug that incorrectly truncated deep stacktraces.
Thanks to @richard-tunein and @pavius for their contributions to this release.
[#477]: https://github.com/uber-go/zap/pull/477
[#465]: https://github.com/uber-go/zap/pull/465
[#460]: https://github.com/uber-go/zap/pull/460
[#470]: https://github.com/uber-go/zap/pull/470
## v1.4.1 (08 Jun 2017)
This release fixes two bugs.
Bugfixes:
* [#435][]: Support a variety of case conventions when unmarshaling levels.
* [#444][]: Fix a panic in the observer.
[#435]: https://github.com/uber-go/zap/pull/435
[#444]: https://github.com/uber-go/zap/pull/444
## v1.4.0 (12 May 2017)
This release adds a few small features and is fully backward-compatible.
Enhancements:
* [#424][]: Add a `LineEnding` field to `EncoderConfig`, allowing users to
override the Unix-style default.
* [#425][]: Preserve time zones when logging times.
* [#431][]: Make `zap.AtomicLevel` implement `fmt.Stringer`, which makes a
variety of operations a bit simpler.
[#424]: https://github.com/uber-go/zap/pull/424
[#425]: https://github.com/uber-go/zap/pull/425
[#431]: https://github.com/uber-go/zap/pull/431
## v1.3.0 (25 Apr 2017)
This release adds an enhancement to zap's testing helpers as well as the
ability to marshal an AtomicLevel. It is fully backward-compatible.
Enhancements:
* [#415][]: Add a substring-filtering helper to zap's observer. This is
particularly useful when testing the `SugaredLogger`.
* [#416][]: Make `AtomicLevel` implement `encoding.TextMarshaler`.
[#415]: https://github.com/uber-go/zap/pull/415
[#416]: https://github.com/uber-go/zap/pull/416
## v1.2.0 (13 Apr 2017)
This release adds a gRPC compatibility wrapper. It is fully backward-compatible.
Enhancements:
* [#402][]: Add a `zapgrpc` package that wraps zap's Logger and implements
`grpclog.Logger`.
[#402]: https://github.com/uber-go/zap/pull/402
## v1.1.0 (31 Mar 2017)
This release fixes two bugs and adds some enhancements to zap's testing helpers.
It is fully backward-compatible.
Bugfixes:
* [#385][]: Fix caller path trimming on Windows.
* [#396][]: Fix a panic when attempting to use non-existent directories with
zap's configuration struct.
Enhancements:
* [#386][]: Add filtering helpers to zaptest's observing logger.
Thanks to @moitias for contributing to this release.
[#385]: https://github.com/uber-go/zap/pull/385
[#396]: https://github.com/uber-go/zap/pull/396
[#386]: https://github.com/uber-go/zap/pull/386
## v1.0.0 (14 Mar 2017)
This is zap's first stable release. All exported APIs are now final, and no
further breaking changes will be made in the 1.x release series. Anyone using a
semver-aware dependency manager should now pin to `^1`.
Breaking changes:
* [#366][]: Add byte-oriented APIs to encoders to log UTF-8 encoded text without
casting from `[]byte` to `string`.
* [#364][]: To support buffering outputs, add `Sync` methods to `zapcore.Core`,
`zap.Logger`, and `zap.SugaredLogger`.
* [#371][]: Rename the `testutils` package to `zaptest`, which is less likely to
clash with other testing helpers.
Bugfixes:
* [#362][]: Make the ISO8601 time formatters fixed-width, which is friendlier
for tab-separated console output.
* [#369][]: Remove the automatic locks in `zapcore.NewCore`, which allows zap to
work with concurrency-safe `WriteSyncer` implementations.
* [#347][]: Stop reporting errors when trying to `fsync` standard out on Linux
systems.
* [#373][]: Report the correct caller from zap's standard library
interoperability wrappers.
Enhancements:
* [#348][]: Add a registry allowing third-party encodings to work with zap's
built-in `Config`.
* [#327][]: Make the representation of logger callers configurable (like times,
levels, and durations).
* [#376][]: Allow third-party encoders to use their own buffer pools, which
removes the last performance advantage that zap's encoders have over plugins.
* [#346][]: Add `CombineWriteSyncers`, a convenience function to tee multiple
`WriteSyncer`s and lock the result.
* [#365][]: Make zap's stacktraces compatible with mid-stack inlining (coming in
Go 1.9).
* [#372][]: Export zap's observing logger as `zaptest/observer`. This makes it
easier for particularly punctilious users to unit test their application's
logging.
Thanks to @suyash, @htrendev, @flisky, @Ulexus, and @skipor for their
contributions to this release.
[#366]: https://github.com/uber-go/zap/pull/366
[#364]: https://github.com/uber-go/zap/pull/364
[#371]: https://github.com/uber-go/zap/pull/371
[#362]: https://github.com/uber-go/zap/pull/362
[#369]: https://github.com/uber-go/zap/pull/369
[#347]: https://github.com/uber-go/zap/pull/347
[#373]: https://github.com/uber-go/zap/pull/373
[#348]: https://github.com/uber-go/zap/pull/348
[#327]: https://github.com/uber-go/zap/pull/327
[#376]: https://github.com/uber-go/zap/pull/376
[#346]: https://github.com/uber-go/zap/pull/346
[#365]: https://github.com/uber-go/zap/pull/365
[#372]: https://github.com/uber-go/zap/pull/372
## v1.0.0-rc.3 (7 Mar 2017)
This is the third release candidate for zap's stable release. There are no
breaking changes.
Bugfixes:
* [#339][]: Byte slices passed to `zap.Any` are now correctly treated as binary blobs
rather than `[]uint8`.
Enhancements:
* [#307][]: Users can opt into colored output for log levels.
* [#353][]: In addition to hijacking the output of the standard library's
package-global logging functions, users can now construct a zap-backed
`log.Logger` instance.
* [#311][]: Frames from common runtime functions and some of zap's internal
machinery are now omitted from stacktraces.
Thanks to @ansel1 and @suyash for their contributions to this release.
[#339]: https://github.com/uber-go/zap/pull/339
[#307]: https://github.com/uber-go/zap/pull/307
[#353]: https://github.com/uber-go/zap/pull/353
[#311]: https://github.com/uber-go/zap/pull/311
## v1.0.0-rc.2 (21 Feb 2017)
This is the second release candidate for zap's stable release. It includes two
breaking changes.
Breaking changes:
* [#316][]: Zap's global loggers are now fully concurrency-safe
(previously, users had to ensure that `ReplaceGlobals` was called before the
loggers were in use). However, they must now be accessed via the `L()` and
`S()` functions. Users can update their projects with
```
gofmt -r "zap.L -> zap.L()" -w .
gofmt -r "zap.S -> zap.S()" -w .
```
* [#309][] and [#317][]: RC1 was mistakenly shipped with invalid
JSON and YAML struct tags on all config structs. This release fixes the tags
and adds static analysis to prevent similar bugs in the future.
Bugfixes:
* [#321][]: Redirecting the standard library's `log` output now
correctly reports the logger's caller.
Enhancements:
* [#325][] and [#333][]: Zap now transparently supports non-standard, rich
errors like those produced by `github.com/pkg/errors`.
* [#326][]: Though `New(nil)` continues to return a no-op logger, `NewNop()` is
now preferred. Users can update their projects with `gofmt -r 'zap.New(nil) ->
zap.NewNop()' -w .`.
* [#300][]: Incorrectly importing zap as `github.com/uber-go/zap` now returns a
more informative error.
Thanks to @skipor and @chapsuk for their contributions to this release.
[#316]: https://github.com/uber-go/zap/pull/316
[#309]: https://github.com/uber-go/zap/pull/309
[#317]: https://github.com/uber-go/zap/pull/317
[#321]: https://github.com/uber-go/zap/pull/321
[#325]: https://github.com/uber-go/zap/pull/325
[#333]: https://github.com/uber-go/zap/pull/333
[#326]: https://github.com/uber-go/zap/pull/326
[#300]: https://github.com/uber-go/zap/pull/300
## v1.0.0-rc.1 (14 Feb 2017)
This is the first release candidate for zap's stable release. There are multiple
breaking changes and improvements from the pre-release version. Most notably:
* **Zap's import path is now "go.uber.org/zap"** &mdash; all users will
need to update their code.
* User-facing types and functions remain in the `zap` package. Code relevant
largely to extension authors is now in the `zapcore` package.
* The `zapcore.Core` type makes it easy for third-party packages to use zap's
internals but provide a different user-facing API.
* `Logger` is now a concrete type instead of an interface.
* A less verbose (though slower) logging API is included by default.
* Package-global loggers `L` and `S` are included.
* A human-friendly console encoder is included.
* A declarative config struct allows common logger configurations to be managed
as configuration instead of code.
* Sampling is more accurate, and doesn't depend on the standard library's shared
timer heap.
## v0.1.0-beta.1 (6 Feb 2017)
This is a minor version, tagged to allow users to pin to the pre-1.0 APIs and
upgrade at their leisure. Since this is the first tagged release, there are no
backward compatibility concerns and all functionality is new.
Early zap adopters should pin to the 0.1.x minor version until they're ready to
upgrade to the upcoming stable release.

75
vendor/go.uber.org/zap/CODE_OF_CONDUCT.md generated vendored Normal file
View File

@@ -0,0 +1,75 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an
appointed representative at an online or offline event. Representation of a
project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at oss-conduct@uber.com. The project
team will review and investigate all complaints, and will respond in a way
that it deems appropriate to the circumstances. The project team is obligated
to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
[http://contributor-covenant.org/version/1/4][version].
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

70
vendor/go.uber.org/zap/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,70 @@
# Contributing
We'd love your help making zap the very best structured logging library in Go!
If you'd like to add new exported APIs, please [open an issue][open-issue]
describing your proposal &mdash; discussing API changes ahead of time makes
pull request review much smoother. In your issue, pull request, and any other
communications, please remember to treat your fellow contributors with
respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously.
Note that you'll need to sign [Uber's Contributor License Agreement][cla]
before we can accept any of your contributions. If necessary, a bot will remind
you to accept the CLA when you open your pull request.
## Setup
[Fork][fork], then clone the repository:
```bash
mkdir -p $GOPATH/src/go.uber.org
cd $GOPATH/src/go.uber.org
git clone git@github.com:your_github_username/zap.git
cd zap
git remote add upstream https://github.com/uber-go/zap.git
git fetch upstream
```
Make sure that the tests and the linters pass:
```bash
make test
make lint
```
## Making Changes
Start by creating a new branch for your changes:
```bash
cd $GOPATH/src/go.uber.org/zap
git checkout master
git fetch upstream
git rebase upstream/master
git checkout -b cool_new_feature
```
Make your changes, then ensure that `make lint` and `make test` still pass. If
you're satisfied with your changes, push them to your fork.
```bash
git push origin cool_new_feature
```
Then use the GitHub UI to open a pull request.
At this point, you're waiting on us to review your changes. We _try_ to respond
to issues and pull requests within a few business days, and we may suggest some
improvements or alternatives. Once your changes are approved, one of the
project maintainers will merge them.
We're much more likely to approve your changes if you:
- Add tests for new functionality.
- Write a [good commit message][commit-message].
- Maintain backward compatibility.
[fork]: https://github.com/uber-go/zap/fork
[open-issue]: https://github.com/uber-go/zap/issues/new
[cla]: https://cla-assistant.io/uber-go/zap
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

164
vendor/go.uber.org/zap/FAQ.md generated vendored Normal file
View File

@@ -0,0 +1,164 @@
# Frequently Asked Questions
## Design
### Why spend so much effort on logger performance?
Of course, most applications won't notice the impact of a slow logger: they
already take tens or hundreds of milliseconds for each operation, so an extra
millisecond doesn't matter.
On the other hand, why *not* make structured logging fast? The `SugaredLogger`
isn't any harder to use than other logging packages, and the `Logger` makes
structured logging possible in performance-sensitive contexts. Across a fleet
of Go microservices, making each application even slightly more efficient adds
up quickly.
### Why aren't `Logger` and `SugaredLogger` interfaces?
Unlike the familiar `io.Writer` and `http.Handler`, `Logger` and
`SugaredLogger` interfaces would include *many* methods. As [Rob Pike points
out][go-proverbs], "The bigger the interface, the weaker the abstraction."
Interfaces are also rigid &mdash; *any* change requires releasing a new major
version, since it breaks all third-party implementations.
Making the `Logger` and `SugaredLogger` concrete types doesn't sacrifice much
abstraction, and it lets us add methods without introducing breaking changes.
Your applications should define and depend upon an interface that includes
just the methods you use.
### Why are some of my logs missing?
Logs are dropped intentionally by zap when sampling is enabled. The production
configuration (as returned by `NewProductionConfig()` enables sampling which will
cause repeated logs within a second to be sampled. See more details on why sampling
is enabled in [Why sample application logs](https://github.com/uber-go/zap/blob/master/FAQ.md#why-sample-application-logs).
### Why sample application logs?
Applications often experience runs of errors, either because of a bug or
because of a misbehaving user. Logging errors is usually a good idea, but it
can easily make this bad situation worse: not only is your application coping
with a flood of errors, it's also spending extra CPU cycles and I/O logging
those errors. Since writes are typically serialized, logging limits throughput
when you need it most.
Sampling fixes this problem by dropping repetitive log entries. Under normal
conditions, your application writes out every entry. When similar entries are
logged hundreds or thousands of times each second, though, zap begins dropping
duplicates to preserve throughput.
### Why do the structured logging APIs take a message in addition to fields?
Subjectively, we find it helpful to accompany structured context with a brief
description. This isn't critical during development, but it makes debugging
and operating unfamiliar systems much easier.
More concretely, zap's sampling algorithm uses the message to identify
duplicate entries. In our experience, this is a practical middle ground
between random sampling (which often drops the exact entry that you need while
debugging) and hashing the complete entry (which is prohibitively expensive).
### Why include package-global loggers?
Since so many other logging packages include a global logger, many
applications aren't designed to accept loggers as explicit parameters.
Changing function signatures is often a breaking change, so zap includes
global loggers to simplify migration.
Avoid them where possible.
### Why include dedicated Panic and Fatal log levels?
In general, application code should handle errors gracefully instead of using
`panic` or `os.Exit`. However, every rule has exceptions, and it's common to
crash when an error is truly unrecoverable. To avoid losing any information
&mdash; especially the reason for the crash &mdash; the logger must flush any
buffered entries before the process exits.
Zap makes this easy by offering `Panic` and `Fatal` logging methods that
automatically flush before exiting. Of course, this doesn't guarantee that
logs will never be lost, but it eliminates a common error.
See the discussion in uber-go/zap#207 for more details.
### What's `DPanic`?
`DPanic` stands for "panic in development." In development, it logs at
`PanicLevel`; otherwise, it logs at `ErrorLevel`. `DPanic` makes it easier to
catch errors that are theoretically possible, but shouldn't actually happen,
*without* crashing in production.
If you've ever written code like this, you need `DPanic`:
```go
if err != nil {
panic(fmt.Sprintf("shouldn't ever get here: %v", err))
}
```
## Installation
### What does the error `expects import "go.uber.org/zap"` mean?
Either zap was installed incorrectly or you're referencing the wrong package
name in your code.
Zap's source code happens to be hosted on GitHub, but the [import
path][import-path] is `go.uber.org/zap`. This gives us, the project
maintainers, the freedom to move the source code if necessary. However, it
means that you need to take a little care when installing and using the
package.
If you follow two simple rules, everything should work: install zap with `go
get -u go.uber.org/zap`, and always import it in your code with `import
"go.uber.org/zap"`. Your code shouldn't contain *any* references to
`github.com/uber-go/zap`.
## Usage
### Does zap support log rotation?
Zap doesn't natively support rotating log files, since we prefer to leave this
to an external program like `logrotate`.
However, it's easy to integrate a log rotation package like
[`gopkg.in/natefinch/lumberjack.v2`][lumberjack] as a `zapcore.WriteSyncer`.
```go
// lumberjack.Logger is already safe for concurrent use, so we don't need to
// lock it.
w := zapcore.AddSync(&lumberjack.Logger{
Filename: "/var/log/myapp/foo.log",
MaxSize: 500, // megabytes
MaxBackups: 3,
MaxAge: 28, // days
})
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
w,
zap.InfoLevel,
)
logger := zap.New(core)
```
## Extensions
We'd love to support every logging need within zap itself, but we're only
familiar with a handful of log ingestion systems, flag-parsing packages, and
the like. Rather than merging code that we can't effectively debug and
support, we'd rather grow an ecosystem of zap extensions.
We're aware of the following extensions, but haven't used them ourselves:
| Package | Integration |
| --- | --- |
| `github.com/tchap/zapext` | Sentry, syslog |
| `github.com/fgrosse/zaptest` | Ginkgo |
| `github.com/blendle/zapdriver` | Stackdriver |
| `github.com/moul/zapgorm` | Gorm |
| `github.com/moul/zapfilter` | Advanced filtering rules |
[go-proverbs]: https://go-proverbs.github.io/
[import-path]: https://golang.org/cmd/go/#hdr-Remote_import_paths
[lumberjack]: https://godoc.org/gopkg.in/natefinch/lumberjack.v2

19
vendor/go.uber.org/zap/LICENSE.txt generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2016-2017 Uber Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

76
vendor/go.uber.org/zap/Makefile generated vendored Normal file
View File

@@ -0,0 +1,76 @@
# Directory containing the Makefile.
PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
export GOBIN ?= $(PROJECT_ROOT)/bin
export PATH := $(GOBIN):$(PATH)
GOVULNCHECK = $(GOBIN)/govulncheck
BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem
# Directories containing independent Go modules.
MODULE_DIRS = . ./exp ./benchmarks ./zapgrpc/internal/test
# Directories that we want to track coverage for.
COVER_DIRS = . ./exp
.PHONY: all
all: lint test
.PHONY: lint
lint: golangci-lint tidy-lint license-lint
.PHONY: golangci-lint
golangci-lint:
@$(foreach mod,$(MODULE_DIRS), \
(cd $(mod) && \
echo "[lint] golangci-lint: $(mod)" && \
golangci-lint run --path-prefix $(mod)) &&) true
.PHONY: tidy
tidy:
@$(foreach dir,$(MODULE_DIRS), \
(cd $(dir) && go mod tidy) &&) true
.PHONY: tidy-lint
tidy-lint:
@$(foreach mod,$(MODULE_DIRS), \
(cd $(mod) && \
echo "[lint] tidy: $(mod)" && \
go mod tidy && \
git diff --exit-code -- go.mod go.sum) &&) true
.PHONY: license-lint
license-lint:
./checklicense.sh
$(GOVULNCHECK):
cd tools && go install golang.org/x/vuln/cmd/govulncheck
.PHONY: test
test:
@$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go test -race ./...) &&) true
.PHONY: cover
cover:
@$(foreach dir,$(COVER_DIRS), ( \
cd $(dir) && \
go test -race -coverprofile=cover.out -coverpkg=./... ./... \
&& go tool cover -html=cover.out -o cover.html) &&) true
.PHONY: bench
BENCH ?= .
bench:
@$(foreach dir,$(MODULE_DIRS), ( \
cd $(dir) && \
go list ./... | xargs -n1 go test -bench=$(BENCH) -run="^$$" $(BENCH_FLAGS) \
) &&) true
.PHONY: updatereadme
updatereadme:
rm -f README.md
cat .readme.tmpl | go run internal/readme/readme.go > README.md
.PHONY: vulncheck
vulncheck: $(GOVULNCHECK)
$(GOVULNCHECK) ./...

137
vendor/go.uber.org/zap/README.md generated vendored Normal file
View File

@@ -0,0 +1,137 @@
# :zap: zap [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Blazing fast, structured, leveled logging in Go.
## Installation
`go get -u go.uber.org/zap`
Note that zap only supports the two most recent minor versions of Go.
## Quick Start
In contexts where performance is nice, but not critical, use the
`SugaredLogger`. It's 4-10x faster than other structured logging
packages and includes both structured and `printf`-style APIs.
```go
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)
```
When performance and type safety are critical, use the `Logger`. It's even
faster than the `SugaredLogger` and allocates far less, but it only supports
structured logging.
```go
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
```
See the [documentation][doc] and [FAQ](FAQ.md) for more details.
## Performance
For applications that log in the hot path, reflection-based serialization and
string formatting are prohibitively expensive &mdash; they're CPU-intensive
and make many small allocations. Put differently, using `encoding/json` and
`fmt.Fprintf` to log tons of `interface{}`s makes your application slow.
Zap takes a different approach. It includes a reflection-free, zero-allocation
JSON encoder, and the base `Logger` strives to avoid serialization overhead
and allocations wherever possible. By building the high-level `SugaredLogger`
on that foundation, zap lets users *choose* when they need to count every
allocation and when they'd prefer a more familiar, loosely typed API.
As measured by its own [benchmarking suite][], not only is zap more performant
than comparable structured logging packages &mdash; it's also faster than the
standard library. Like all benchmarks, take these with a grain of salt.<sup
id="anchor-versions">[1](#footnote-versions)</sup>
Log a message and 10 fields:
| Package | Time | Time % to zap | Objects Allocated |
| :------ | :--: | :-----------: | :---------------: |
| :zap: zap | 1744 ns/op | +0% | 5 allocs/op
| :zap: zap (sugared) | 2483 ns/op | +42% | 10 allocs/op
| zerolog | 918 ns/op | -47% | 1 allocs/op
| go-kit | 5590 ns/op | +221% | 57 allocs/op
| slog | 5640 ns/op | +223% | 40 allocs/op
| apex/log | 21184 ns/op | +1115% | 63 allocs/op
| logrus | 24338 ns/op | +1296% | 79 allocs/op
| log15 | 26054 ns/op | +1394% | 74 allocs/op
Log a message with a logger that already has 10 fields of context:
| Package | Time | Time % to zap | Objects Allocated |
| :------ | :--: | :-----------: | :---------------: |
| :zap: zap | 193 ns/op | +0% | 0 allocs/op
| :zap: zap (sugared) | 227 ns/op | +18% | 1 allocs/op
| zerolog | 81 ns/op | -58% | 0 allocs/op
| slog | 322 ns/op | +67% | 0 allocs/op
| go-kit | 5377 ns/op | +2686% | 56 allocs/op
| apex/log | 19518 ns/op | +10013% | 53 allocs/op
| log15 | 19812 ns/op | +10165% | 70 allocs/op
| logrus | 21997 ns/op | +11297% | 68 allocs/op
Log a static string, without any context or `printf`-style templating:
| Package | Time | Time % to zap | Objects Allocated |
| :------ | :--: | :-----------: | :---------------: |
| :zap: zap | 165 ns/op | +0% | 0 allocs/op
| :zap: zap (sugared) | 212 ns/op | +28% | 1 allocs/op
| zerolog | 95 ns/op | -42% | 0 allocs/op
| slog | 296 ns/op | +79% | 0 allocs/op
| go-kit | 415 ns/op | +152% | 9 allocs/op
| standard library | 422 ns/op | +156% | 2 allocs/op
| apex/log | 1601 ns/op | +870% | 5 allocs/op
| logrus | 3017 ns/op | +1728% | 23 allocs/op
| log15 | 3469 ns/op | +2002% | 20 allocs/op
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
zap to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors &mdash;
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The zap maintainers keep an eye on
issues and pull requests, but you can also report any negative conduct to
oss-conduct@uber.com. That email list is a private, safe space; even the zap
maintainers don't have access, so don't hesitate to hold us to a high
standard.
<hr>
Released under the [MIT License](LICENSE.txt).
<sup id="footnote-versions">1</sup> In particular, keep in mind that we may be
benchmarking against slightly older versions of other packages. Versions are
pinned in the [benchmarks/go.mod][] file. [](#anchor-versions)
[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap
[doc]: https://pkg.go.dev/go.uber.org/zap
[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg
[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml
[cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/zap
[benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks
[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod

447
vendor/go.uber.org/zap/array.go generated vendored Normal file
View File

@@ -0,0 +1,447 @@
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package zap
import (
"fmt"
"time"
"go.uber.org/zap/zapcore"
)
// Array constructs a field with the given key and ArrayMarshaler. It provides
// a flexible, but still type-safe and efficient, way to add array-like types
// to the logging context. The struct's MarshalLogArray method is called lazily.
func Array(key string, val zapcore.ArrayMarshaler) Field {
return Field{Key: key, Type: zapcore.ArrayMarshalerType, Interface: val}
}
// Bools constructs a field that carries a slice of bools.
func Bools(key string, bs []bool) Field {
return Array(key, bools(bs))
}
// ByteStrings constructs a field that carries a slice of []byte, each of which
// must be UTF-8 encoded text.
func ByteStrings(key string, bss [][]byte) Field {
return Array(key, byteStringsArray(bss))
}
// Complex128s constructs a field that carries a slice of complex numbers.
func Complex128s(key string, nums []complex128) Field {
return Array(key, complex128s(nums))
}
// Complex64s constructs a field that carries a slice of complex numbers.
func Complex64s(key string, nums []complex64) Field {
return Array(key, complex64s(nums))
}
// Durations constructs a field that carries a slice of time.Durations.
func Durations(key string, ds []time.Duration) Field {
return Array(key, durations(ds))
}
// Float64s constructs a field that carries a slice of floats.
func Float64s(key string, nums []float64) Field {
return Array(key, float64s(nums))
}
// Float32s constructs a field that carries a slice of floats.
func Float32s(key string, nums []float32) Field {
return Array(key, float32s(nums))
}
// Ints constructs a field that carries a slice of integers.
func Ints(key string, nums []int) Field {
return Array(key, ints(nums))
}
// Int64s constructs a field that carries a slice of integers.
func Int64s(key string, nums []int64) Field {
return Array(key, int64s(nums))
}
// Int32s constructs a field that carries a slice of integers.
func Int32s(key string, nums []int32) Field {
return Array(key, int32s(nums))
}
// Int16s constructs a field that carries a slice of integers.
func Int16s(key string, nums []int16) Field {
return Array(key, int16s(nums))
}
// Int8s constructs a field that carries a slice of integers.
func Int8s(key string, nums []int8) Field {
return Array(key, int8s(nums))
}
// Objects constructs a field with the given key, holding a list of the
// provided objects that can be marshaled by Zap.
//
// Note that these objects must implement zapcore.ObjectMarshaler directly.
// That is, if you're trying to marshal a []Request, the MarshalLogObject
// method must be declared on the Request type, not its pointer (*Request).
// If it's on the pointer, use ObjectValues.
//
// Given an object that implements MarshalLogObject on the value receiver, you
// can log a slice of those objects with Objects like so:
//
// type Author struct{ ... }
// func (a Author) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
// var authors []Author = ...
// logger.Info("loading article", zap.Objects("authors", authors))
//
// Similarly, given a type that implements MarshalLogObject on its pointer
// receiver, you can log a slice of pointers to that object with Objects like
// so:
//
// type Request struct{ ... }
// func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
// var requests []*Request = ...
// logger.Info("sending requests", zap.Objects("requests", requests))
//
// If instead, you have a slice of values of such an object, use the
// ObjectValues constructor.
//
// var requests []Request = ...
// logger.Info("sending requests", zap.ObjectValues("requests", requests))
func Objects[T zapcore.ObjectMarshaler](key string, values []T) Field {
return Array(key, objects[T](values))
}
type objects[T zapcore.ObjectMarshaler] []T
func (os objects[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for _, o := range os {
if err := arr.AppendObject(o); err != nil {
return err
}
}
return nil
}
// ObjectMarshalerPtr is a constraint that specifies that the given type
// implements zapcore.ObjectMarshaler on a pointer receiver.
type ObjectMarshalerPtr[T any] interface {
*T
zapcore.ObjectMarshaler
}
// ObjectValues constructs a field with the given key, holding a list of the
// provided objects, where pointers to these objects can be marshaled by Zap.
//
// Note that pointers to these objects must implement zapcore.ObjectMarshaler.
// That is, if you're trying to marshal a []Request, the MarshalLogObject
// method must be declared on the *Request type, not the value (Request).
// If it's on the value, use Objects.
//
// Given an object that implements MarshalLogObject on the pointer receiver,
// you can log a slice of those objects with ObjectValues like so:
//
// type Request struct{ ... }
// func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error
//
// var requests []Request = ...
// logger.Info("sending requests", zap.ObjectValues("requests", requests))
//
// If instead, you have a slice of pointers of such an object, use the Objects
// field constructor.
//
// var requests []*Request = ...
// logger.Info("sending requests", zap.Objects("requests", requests))
func ObjectValues[T any, P ObjectMarshalerPtr[T]](key string, values []T) Field {
return Array(key, objectValues[T, P](values))
}
type objectValues[T any, P ObjectMarshalerPtr[T]] []T
func (os objectValues[T, P]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range os {
// It is necessary for us to explicitly reference the "P" type.
// We cannot simply pass "&os[i]" to AppendObject because its type
// is "*T", which the type system does not consider as
// implementing ObjectMarshaler.
// Only the type "P" satisfies ObjectMarshaler, which we have
// to convert "*T" to explicitly.
var p P = &os[i]
if err := arr.AppendObject(p); err != nil {
return err
}
}
return nil
}
// Strings constructs a field that carries a slice of strings.
func Strings(key string, ss []string) Field {
return Array(key, stringArray(ss))
}
// Stringers constructs a field with the given key, holding a list of the
// output provided by the value's String method
//
// Given an object that implements String on the value receiver, you
// can log a slice of those objects with Objects like so:
//
// type Request struct{ ... }
// func (a Request) String() string
//
// var requests []Request = ...
// logger.Info("sending requests", zap.Stringers("requests", requests))
//
// Note that these objects must implement fmt.Stringer directly.
// That is, if you're trying to marshal a []Request, the String method
// must be declared on the Request type, not its pointer (*Request).
func Stringers[T fmt.Stringer](key string, values []T) Field {
return Array(key, stringers[T](values))
}
type stringers[T fmt.Stringer] []T
func (os stringers[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for _, o := range os {
arr.AppendString(o.String())
}
return nil
}
// Times constructs a field that carries a slice of time.Times.
func Times(key string, ts []time.Time) Field {
return Array(key, times(ts))
}
// Uints constructs a field that carries a slice of unsigned integers.
func Uints(key string, nums []uint) Field {
return Array(key, uints(nums))
}
// Uint64s constructs a field that carries a slice of unsigned integers.
func Uint64s(key string, nums []uint64) Field {
return Array(key, uint64s(nums))
}
// Uint32s constructs a field that carries a slice of unsigned integers.
func Uint32s(key string, nums []uint32) Field {
return Array(key, uint32s(nums))
}
// Uint16s constructs a field that carries a slice of unsigned integers.
func Uint16s(key string, nums []uint16) Field {
return Array(key, uint16s(nums))
}
// Uint8s constructs a field that carries a slice of unsigned integers.
func Uint8s(key string, nums []uint8) Field {
return Array(key, uint8s(nums))
}
// Uintptrs constructs a field that carries a slice of pointer addresses.
func Uintptrs(key string, us []uintptr) Field {
return Array(key, uintptrs(us))
}
// Errors constructs a field that carries a slice of errors.
func Errors(key string, errs []error) Field {
return Array(key, errArray(errs))
}
type bools []bool
func (bs bools) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bs {
arr.AppendBool(bs[i])
}
return nil
}
type byteStringsArray [][]byte
func (bss byteStringsArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range bss {
arr.AppendByteString(bss[i])
}
return nil
}
type complex128s []complex128
func (nums complex128s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex128(nums[i])
}
return nil
}
type complex64s []complex64
func (nums complex64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendComplex64(nums[i])
}
return nil
}
type durations []time.Duration
func (ds durations) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ds {
arr.AppendDuration(ds[i])
}
return nil
}
type float64s []float64
func (nums float64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat64(nums[i])
}
return nil
}
type float32s []float32
func (nums float32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendFloat32(nums[i])
}
return nil
}
type ints []int
func (nums ints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt(nums[i])
}
return nil
}
type int64s []int64
func (nums int64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt64(nums[i])
}
return nil
}
type int32s []int32
func (nums int32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt32(nums[i])
}
return nil
}
type int16s []int16
func (nums int16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt16(nums[i])
}
return nil
}
type int8s []int8
func (nums int8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendInt8(nums[i])
}
return nil
}
type stringArray []string
func (ss stringArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ss {
arr.AppendString(ss[i])
}
return nil
}
type times []time.Time
func (ts times) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range ts {
arr.AppendTime(ts[i])
}
return nil
}
type uints []uint
func (nums uints) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint(nums[i])
}
return nil
}
type uint64s []uint64
func (nums uint64s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint64(nums[i])
}
return nil
}
type uint32s []uint32
func (nums uint32s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint32(nums[i])
}
return nil
}
type uint16s []uint16
func (nums uint16s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint16(nums[i])
}
return nil
}
type uint8s []uint8
func (nums uint8s) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUint8(nums[i])
}
return nil
}
type uintptrs []uintptr
func (nums uintptrs) MarshalLogArray(arr zapcore.ArrayEncoder) error {
for i := range nums {
arr.AppendUintptr(nums[i])
}
return nil
}

Some files were not shown because too many files have changed in this diff Show More