WIP: Save agent roles integration work before CHORUS rebrand

- Agent roles and coordination features
- Chat API integration testing
- New configuration and workspace management

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-08-01 02:21:11 +10:00
parent 81b473d48f
commit 5978a0b8f5
3713 changed files with 1103925 additions and 59 deletions

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"